Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit fbdebfa

Browse files
committed
[clang-diff] Improve and test getNodeValue
Summary: Use qualified names if available. Reviewers: arphaman Subscribers: klimek Differential Revision: https://reviews.llvm.org/D36186 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@311292 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 0366408 commit fbdebfa

File tree

9 files changed

+132
-55
lines changed

9 files changed

+132
-55
lines changed

include/clang/Tooling/ASTDiff/ASTDiff.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ struct Node {
4545
ast_type_traits::ASTNodeKind getType() const;
4646
StringRef getTypeLabel() const;
4747
bool isLeaf() const { return Children.empty(); }
48+
llvm::Optional<StringRef> getIdentifier() const;
49+
llvm::Optional<std::string> getQualifiedIdentifier() const;
4850
};
4951

5052
class ASTDiff {

lib/Tooling/ASTDiff/ASTDiff.cpp

Lines changed: 87 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ class SyntaxTree::Impl {
149149

150150
std::string getNodeValue(NodeId Id) const;
151151
std::string getNodeValue(const Node &Node) const;
152+
std::string getDeclValue(const Decl *D) const;
153+
std::string getStmtValue(const Stmt *S) const;
152154

153155
private:
154156
/// Nodes in preorder.
@@ -268,9 +270,6 @@ struct PreorderVisitor : public RecursiveASTVisitor<PreorderVisitor> {
268270
};
269271
} // end anonymous namespace
270272

271-
SyntaxTree::Impl::Impl(SyntaxTree *Parent, const ASTContext &AST)
272-
: Impl(Parent, AST.getTranslationUnitDecl(), AST) {}
273-
274273
SyntaxTree::Impl::Impl(SyntaxTree *Parent, Decl *N, const ASTContext &AST)
275274
: Parent(Parent), AST(AST) {
276275
NodeCountVisitor NodeCounter(*this);
@@ -372,49 +371,82 @@ std::string SyntaxTree::Impl::getNodeValue(NodeId Id) const {
372371

373372
std::string SyntaxTree::Impl::getNodeValue(const Node &N) const {
374373
const DynTypedNode &DTN = N.ASTNode;
375-
if (auto *X = DTN.get<BinaryOperator>())
376-
return X->getOpcodeStr();
377-
if (auto *X = DTN.get<AccessSpecDecl>()) {
378-
CharSourceRange Range(X->getSourceRange(), false);
374+
if (auto *S = DTN.get<Stmt>())
375+
return getStmtValue(S);
376+
if (auto *D = DTN.get<Decl>())
377+
return getDeclValue(D);
378+
llvm_unreachable("Fatal: unhandled AST node.\n");
379+
}
380+
381+
std::string SyntaxTree::Impl::getDeclValue(const Decl *D) const {
382+
std::string Value;
383+
PrintingPolicy TypePP(AST.getLangOpts());
384+
TypePP.AnonymousTagLocations = false;
385+
386+
if (auto *V = dyn_cast<ValueDecl>(D)) {
387+
Value += V->getQualifiedNameAsString() + "(" +
388+
V->getType().getAsString(TypePP) + ")";
389+
if (auto *C = dyn_cast<CXXConstructorDecl>(D)) {
390+
for (auto *Init : C->inits()) {
391+
if (!Init->isWritten())
392+
continue;
393+
if (Init->isBaseInitializer()) {
394+
Value += Init->getBaseClass()->getCanonicalTypeInternal().getAsString(
395+
TypePP);
396+
} else if (Init->isDelegatingInitializer()) {
397+
Value += C->getNameAsString();
398+
} else {
399+
assert(Init->isAnyMemberInitializer());
400+
Value += Init->getMember()->getQualifiedNameAsString();
401+
}
402+
Value += ",";
403+
}
404+
}
405+
return Value;
406+
}
407+
if (auto *N = dyn_cast<NamedDecl>(D))
408+
Value += N->getQualifiedNameAsString() + ";";
409+
if (auto *T = dyn_cast<TypedefNameDecl>(D))
410+
return Value + T->getUnderlyingType().getAsString(TypePP) + ";";
411+
if (auto *T = dyn_cast<TypeDecl>(D))
412+
if (T->getTypeForDecl())
413+
Value +=
414+
T->getTypeForDecl()->getCanonicalTypeInternal().getAsString(TypePP) +
415+
";";
416+
if (auto *U = dyn_cast<UsingDirectiveDecl>(D))
417+
return U->getNominatedNamespace()->getName();
418+
if (auto *A = dyn_cast<AccessSpecDecl>(D)) {
419+
CharSourceRange Range(A->getSourceRange(), false);
379420
return Lexer::getSourceText(Range, AST.getSourceManager(),
380421
AST.getLangOpts());
381422
}
382-
if (auto *X = DTN.get<IntegerLiteral>()) {
423+
return Value;
424+
}
425+
426+
std::string SyntaxTree::Impl::getStmtValue(const Stmt *S) const {
427+
if (auto *U = dyn_cast<UnaryOperator>(S))
428+
return UnaryOperator::getOpcodeStr(U->getOpcode());
429+
if (auto *B = dyn_cast<BinaryOperator>(S))
430+
return B->getOpcodeStr();
431+
if (auto *M = dyn_cast<MemberExpr>(S))
432+
return M->getMemberDecl()->getQualifiedNameAsString();
433+
if (auto *I = dyn_cast<IntegerLiteral>(S)) {
383434
SmallString<256> Str;
384-
X->getValue().toString(Str, /*Radix=*/10, /*Signed=*/false);
435+
I->getValue().toString(Str, /*Radix=*/10, /*Signed=*/false);
385436
return Str.str();
386437
}
387-
if (auto *X = DTN.get<StringLiteral>())
388-
return X->getString();
389-
if (auto *X = DTN.get<ValueDecl>())
390-
return X->getNameAsString() + "(" + X->getType().getAsString() + ")";
391-
if (DTN.get<DeclStmt>() || DTN.get<TranslationUnitDecl>())
392-
return "";
393-
std::string Value;
394-
if (auto *X = DTN.get<DeclRefExpr>()) {
395-
if (X->hasQualifier()) {
396-
llvm::raw_string_ostream OS(Value);
397-
PrintingPolicy PP(AST.getLangOpts());
398-
X->getQualifier()->print(OS, PP);
399-
}
400-
Value += X->getDecl()->getNameAsString();
401-
return Value;
438+
if (auto *F = dyn_cast<FloatingLiteral>(S)) {
439+
SmallString<256> Str;
440+
F->getValue().toString(Str);
441+
return Str.str();
402442
}
403-
if (auto *X = DTN.get<NamedDecl>())
404-
Value += X->getNameAsString() + ";";
405-
if (auto *X = DTN.get<TypedefNameDecl>())
406-
return Value + X->getUnderlyingType().getAsString() + ";";
407-
if (DTN.get<NamespaceDecl>())
408-
return Value;
409-
if (auto *X = DTN.get<TypeDecl>())
410-
if (X->getTypeForDecl())
411-
Value +=
412-
X->getTypeForDecl()->getCanonicalTypeInternal().getAsString() + ";";
413-
if (DTN.get<Decl>())
414-
return Value;
415-
if (DTN.get<Stmt>())
416-
return "";
417-
llvm_unreachable("Fatal: unhandled AST node.\n");
443+
if (auto *D = dyn_cast<DeclRefExpr>(S))
444+
return D->getDecl()->getQualifiedNameAsString();
445+
if (auto *String = dyn_cast<StringLiteral>(S))
446+
return String->getString();
447+
if (auto *B = dyn_cast<CXXBoolLiteralExpr>(S))
448+
return B->getValue() ? "true" : "false";
449+
return "";
418450
}
419451

420452
/// Identifies a node in a subtree by its postorder offset, starting at 1.
@@ -637,6 +669,22 @@ ast_type_traits::ASTNodeKind Node::getType() const {
637669

638670
StringRef Node::getTypeLabel() const { return getType().asStringRef(); }
639671

672+
llvm::Optional<std::string> Node::getQualifiedIdentifier() const {
673+
if (auto *ND = ASTNode.get<NamedDecl>()) {
674+
if (ND->getDeclName().isIdentifier())
675+
return ND->getQualifiedNameAsString();
676+
}
677+
return llvm::None;
678+
}
679+
680+
llvm::Optional<StringRef> Node::getIdentifier() const {
681+
if (auto *ND = ASTNode.get<NamedDecl>()) {
682+
if (ND->getDeclName().isIdentifier())
683+
return ND->getName();
684+
}
685+
return llvm::None;
686+
}
687+
640688
namespace {
641689
// Compares nodes by their depth.
642690
struct HeightLess {

test/Tooling/clang-diff-ast.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,31 @@
55
// CHECK: {{^}} NamespaceDecl: test;(
66
namespace test {
77

8-
// CHECK: {{^}} FunctionDecl: f(
8+
// CHECK: {{^}} FunctionDecl: test::f(
99
// CHECK: CompoundStmt(
1010
void f() {
1111
// CHECK: VarDecl: i(int)(
1212
// CHECK: IntegerLiteral: 1
1313
auto i = 1;
14+
// CHECK: FloatingLiteral: 1.5(
15+
auto r = 1.5;
16+
// CHECK: CXXBoolLiteralExpr: true(
17+
auto b = true;
1418
// CHECK: CallExpr(
1519
// CHECK-NOT: ImplicitCastExpr
16-
// CHECK-NEXT: DeclRefExpr: f(
20+
// CHECK: DeclRefExpr: test::f(
1721
f();
22+
// CHECK: UnaryOperator: ++(
23+
++i;
1824
// CHECK: BinaryOperator: =(
1925
i = i;
2026
}
2127

2228
} // end namespace test
2329

30+
// CHECK: UsingDirectiveDecl: test(
31+
using namespace test;
32+
2433
// CHECK: TypedefDecl: nat;unsigned int;(
2534
typedef unsigned nat;
2635
// CHECK: TypeAliasDecl: real;double;(
@@ -29,10 +38,10 @@ using real = double;
2938
class Base {
3039
};
3140

32-
// CHECK: CXXRecordDecl: X;class X;(
41+
// CHECK: CXXRecordDecl: X;X;(
3342
class X : Base {
3443
int m;
35-
// CHECK: CXXMethodDecl: foo(const char *(int)
44+
// CHECK: CXXMethodDecl: X::foo(const char *(int)
3645
// CHECK: ParmVarDecl: i(int)(
3746
const char *foo(int i) {
3847
if (i == 0)
@@ -44,11 +53,16 @@ class X : Base {
4453

4554
// CHECK: AccessSpecDecl: public(
4655
public:
47-
// CHECK: CXXConstructorDecl: X(void (char, int){{( __attribute__\(\(thiscall\)\))?}})(
48-
X(char, int) : Base(), m(0) {
49-
// CHECK: MemberExpr(
56+
int not_initialized;
57+
// All initialized members, bases and delegating initializers are are
58+
// appended, separated by commas.
59+
// CHECK: CXXConstructorDecl: X::X(void (char, int){{( __attribute__\(\(thiscall\)\))?}})Base,X::m,(
60+
X(char c, int) : Base(), m(0) {
61+
// CHECK: MemberExpr: X::m(
5062
int x = m;
5163
}
64+
// CHECK: CXXConstructorDecl: X::X(void (char))X,(
65+
X(char s) : X(s, 4) {}
5266
};
5367

5468
#define M (void)1

test/Tooling/clang-diff-basic.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@ void foo() {
1111
}
1212
}
1313

14-
// CHECK: Match DeclRefExpr: foo{{.*}} to DeclRefExpr: inner::foo
14+
// CHECK: Match DeclRefExpr: src::foo{{.*}} to DeclRefExpr: dst::inner::foo
1515
void main() { inner::foo(); }
1616

1717
// CHECK: Match StringLiteral: foo{{.*}} to StringLiteral: foo
1818
const char *b = "f" "o" "o";
1919

2020
// unsigned is canonicalized to unsigned int
21-
// CHECK: Match TypedefDecl: nat;unsigned int;{{.*}} to TypedefDecl: nat;unsigned int;
21+
// CHECK: Match TypedefDecl: src::nat;unsigned int;{{.*}} to TypedefDecl: dst::nat;unsigned int;
2222
typedef unsigned nat;
2323

24-
// CHECK: Match VarDecl: p(int){{.*}} to VarDecl: prod(double)
25-
// CHECK: Update VarDecl: p(int){{.*}} to prod(double)
24+
// CHECK: Match VarDecl: src::p(int){{.*}} to VarDecl: dst::prod(double)
25+
// CHECK: Update VarDecl: src::p(int){{.*}} to dst::prod(double)
2626
// CHECK: Match BinaryOperator: *{{.*}} to BinaryOperator: *
2727
double prod = 1 * 2 * 10;
2828
// CHECK: Update DeclRefExpr
@@ -49,7 +49,7 @@ int um = 1 + 7;
4949

5050
namespace {
5151
// match with parents of different type
52-
// CHECK: Match FunctionDecl: f1{{.*}} to FunctionDecl: f1
52+
// CHECK: Match FunctionDecl: f1{{.*}} to FunctionDecl: (anonymous namespace)::f1
5353
void f1() {{ (void) __func__;;; }}
5454
}
5555

test/Tooling/clang-diff-bottomup.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ void f2() { ;; {{;}} }
1616
void f1() {
1717
// CompoundStmt: 3 matched descendants, subtree sizes 4 and 5
1818
// Jaccard similarity = 3 / (4 + 5 - 3) = 3 / 6 >= 0.5
19-
// CHECK: Match FunctionDecl: f1(void (void))(1) to FunctionDecl: f1(void (void))(1)
19+
// CHECK: Match FunctionDecl: f1(void ())(1) to FunctionDecl: f1(void ())(1)
2020
// CHECK: Match CompoundStmt(2) to CompoundStmt(2)
2121
// CHECK: Match CompoundStmt(4) to CompoundStmt(3)
2222
// CHECK: Match CompoundStmt(5) to CompoundStmt(4)

test/Tooling/clang-diff-html.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
// match, move
1212
// CHECK: <span id='L[[L:[0-9]+]]' tid='R[[R:[0-9]+]]' title='FunctionDecl
1313
// CHECK-NEXT: [[L]] -> [[R]]
14-
// CHECK-NEXT: foo(void (void))' class='m'>void foo()
14+
// CHECK-NEXT: src::foo(void ())' class='u m'>void foo()
1515

1616
// match
1717
// CHECK: <span id='L[[L:[0-9]+]]' tid='R[[R:[0-9]+]]' title='FunctionDecl
1818
// CHECK-NEXT: [[L]] -> [[R]]
19-
// CHECK-NEXT: main(void (void))'>void main()
19+
// CHECK-NEXT: src::main(void ())' class='u'>void main()
2020

2121
// deletion
2222
// CHECK: <span id='L[[L:[0-9]+]]' tid='R-1' title='IntegerLiteral

test/Tooling/clang-diff-opt.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,5 @@ void f3() {
4141
// CHECK: Delete NullStmt(22)
4242
;; {{;;;;;;}}
4343
}
44+
4445
#endif

test/Tooling/clang-diff-topdown.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %clang_cc1 -E %s > %t.src.cpp
22
// RUN: %clang_cc1 -E %s > %t.dst.cpp -DDEST
3-
// RUN: clang-diff -dump-matches -stop-after=topdown %t.src.cpp %t.dst.cpp -- | FileCheck %s
3+
// RUN: clang-diff -dump-matches -stop-after=topdown %t.src.cpp %t.dst.cpp -- -std=c++11 | FileCheck %s
44
//
55
// Test the top-down matching of identical subtrees only.
66

tools/clang-diff/ClangDiff.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,18 @@ static void printNodeAsJson(raw_ostream &OS, diff::SyntaxTree &Tree,
316316
const diff::Node &N = Tree.getNode(Id);
317317
OS << "{";
318318
printNodeAttributes(OS, Tree, Id);
319+
auto Identifier = N.getIdentifier();
320+
auto QualifiedIdentifier = N.getQualifiedIdentifier();
321+
if (Identifier) {
322+
OS << R"(,"identifier":")";
323+
printJsonString(OS, *Identifier);
324+
OS << R"(")";
325+
if (QualifiedIdentifier && *Identifier != *QualifiedIdentifier) {
326+
OS << R"(,"qualified_identifier":")";
327+
printJsonString(OS, *QualifiedIdentifier);
328+
OS << R"(")";
329+
}
330+
}
319331
OS << R"(,"children":[)";
320332
if (N.Children.size() > 0) {
321333
printNodeAsJson(OS, Tree, N.Children[0]);

0 commit comments

Comments
 (0)