Merge remote-tracking branch 'origin/master' into 4.6

Change-Id: I5e73b7e3cc7281e66c699d03f5ab3f92915d0f21
This commit is contained in:
Eike Ziller
2018-01-17 09:47:01 +01:00
137 changed files with 76142 additions and 21072 deletions

View File

@@ -25,7 +25,7 @@ index 944cd775d5..6aba10e5c7 100644
- return nullptr;
+ auto usingDeclPtr = ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
+ prefixAttrs);
+ if (!usingDeclPtr)
+ if (!usingDeclPtr || !usingDeclPtr.get().isSingleDecl())
+ return nullptr;
+ return usingDeclPtr.get().getSingleDecl();
}

View File

@@ -0,0 +1,34 @@
--- /dev/null
+++ b/tools/clang/test/Index/annotate-tokens-unexposed.cpp
@@ -0,0 +1,20 @@
+// RUN: c-index-test -test-annotate-tokens=%s:1:1:16:1 %s -target x86_64-pc-windows-msvc | FileCheck %s
+class Foo
+{
+public:
+ void step(int v);
+ Foo();
+};
+
+void bar()
+{
+ // Introduce a MSInheritanceAttr node on the CXXRecordDecl for Foo. The
+ // existence of this attribute should not mark all cursors for tokens in
+ // Foo as UnexposedAttr.
+ &Foo::step;
+}
+
+Foo::Foo()
+{}
+
+// CHECK-NOT: UnexposedAttr=
--- a/tools/clang/tools/libclang/CIndex.cpp
+++ b/tools/clang/tools/libclang/CIndex.cpp
@@ -1772,7 +1772,7 @@
bool CursorVisitor::VisitAttributes(Decl *D) {
for (const auto *I : D->attrs())
- if (Visit(MakeCXCursor(I, D, TU)))
+ if (!I->isImplicit() && Visit(MakeCXCursor(I, D, TU)))
return true;
return false;

View File

@@ -0,0 +1,266 @@
--- a/tools/clang/lib/AST/DeclPrinter.cpp
+++ b/tools/clang/lib/AST/DeclPrinter.cpp
@@ -608,66 +608,69 @@
}
if (CDecl) {
- bool HasInitializerList = false;
- for (const auto *BMInitializer : CDecl->inits()) {
- if (BMInitializer->isInClassMemberInitializer())
- continue;
-
- if (!HasInitializerList) {
- Proto += " : ";
- Out << Proto;
- Proto.clear();
- HasInitializerList = true;
- } else
- Out << ", ";
+ if (!Policy.TerseOutput) {
+ bool HasInitializerList = false;
+ for (const auto *BMInitializer : CDecl->inits()) {
+ if (BMInitializer->isInClassMemberInitializer())
+ continue;
- if (BMInitializer->isAnyMemberInitializer()) {
- FieldDecl *FD = BMInitializer->getAnyMember();
- Out << *FD;
- } else {
- Out << QualType(BMInitializer->getBaseClass(), 0).getAsString(Policy);
- }
-
- Out << "(";
- if (!BMInitializer->getInit()) {
- // Nothing to print
- } else {
- Expr *Init = BMInitializer->getInit();
- if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init))
- Init = Tmp->getSubExpr();
-
- Init = Init->IgnoreParens();
-
- Expr *SimpleInit = nullptr;
- Expr **Args = nullptr;
- unsigned NumArgs = 0;
- if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
- Args = ParenList->getExprs();
- NumArgs = ParenList->getNumExprs();
- } else if (CXXConstructExpr *Construct
- = dyn_cast<CXXConstructExpr>(Init)) {
- Args = Construct->getArgs();
- NumArgs = Construct->getNumArgs();
+ if (!HasInitializerList) {
+ Proto += " : ";
+ Out << Proto;
+ Proto.clear();
+ HasInitializerList = true;
} else
- SimpleInit = Init;
-
- if (SimpleInit)
- SimpleInit->printPretty(Out, nullptr, Policy, Indentation);
- else {
- for (unsigned I = 0; I != NumArgs; ++I) {
- assert(Args[I] != nullptr && "Expected non-null Expr");
- if (isa<CXXDefaultArgExpr>(Args[I]))
- break;
-
- if (I)
- Out << ", ";
- Args[I]->printPretty(Out, nullptr, Policy, Indentation);
+ Out << ", ";
+
+ if (BMInitializer->isAnyMemberInitializer()) {
+ FieldDecl *FD = BMInitializer->getAnyMember();
+ Out << *FD;
+ } else {
+ Out << QualType(BMInitializer->getBaseClass(), 0)
+ .getAsString(Policy);
+ }
+
+ Out << "(";
+ if (!BMInitializer->getInit()) {
+ // Nothing to print
+ } else {
+ Expr *Init = BMInitializer->getInit();
+ if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init))
+ Init = Tmp->getSubExpr();
+
+ Init = Init->IgnoreParens();
+
+ Expr *SimpleInit = nullptr;
+ Expr **Args = nullptr;
+ unsigned NumArgs = 0;
+ if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
+ Args = ParenList->getExprs();
+ NumArgs = ParenList->getNumExprs();
+ } else if (CXXConstructExpr *Construct =
+ dyn_cast<CXXConstructExpr>(Init)) {
+ Args = Construct->getArgs();
+ NumArgs = Construct->getNumArgs();
+ } else
+ SimpleInit = Init;
+
+ if (SimpleInit)
+ SimpleInit->printPretty(Out, nullptr, Policy, Indentation);
+ else {
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ assert(Args[I] != nullptr && "Expected non-null Expr");
+ if (isa<CXXDefaultArgExpr>(Args[I]))
+ break;
+
+ if (I)
+ Out << ", ";
+ Args[I]->printPretty(Out, nullptr, Policy, Indentation);
+ }
}
}
+ Out << ")";
+ if (BMInitializer->isPackExpansion())
+ Out << "...";
}
- Out << ")";
- if (BMInitializer->isPackExpansion())
- Out << "...";
}
} else if (!ConversionDecl && !isa<CXXDestructorDecl>(D)) {
if (FT && FT->hasTrailingReturn()) {
@@ -712,7 +715,7 @@
if (D->getBody())
D->getBody()->printPretty(Out, nullptr, SubPolicy, Indentation);
} else {
- if (isa<CXXConstructorDecl>(*D))
+ if (!Policy.TerseOutput && isa<CXXConstructorDecl>(*D))
Out << " {}";
}
}
--- a/tools/clang/test/Index/comment-cplus-decls.cpp
+++ b/tools/clang/test/Index/comment-cplus-decls.cpp
@@ -46,7 +46,7 @@
data* reserved;
};
// CHECK: <Declaration>class Test {}</Declaration>
-// CHECK: <Declaration>Test() : reserved(new Test::data()) {}</Declaration>
+// CHECK: <Declaration>Test()</Declaration>
// CHECK: <Declaration>unsigned int getID() const</Declaration>
// CHECK: <Declaration>~Test(){{( noexcept)?}}</Declaration>
// CHECK: <Declaration>Test::data *reserved</Declaration>
--- a/tools/clang/unittests/AST/DeclPrinterTest.cpp
+++ b/tools/clang/unittests/AST/DeclPrinterTest.cpp
@@ -31,18 +31,25 @@
namespace {
-void PrintDecl(raw_ostream &Out, const ASTContext *Context, const Decl *D) {
+using PrintingPolicyModifier = void (*)(PrintingPolicy &policy);
+
+void PrintDecl(raw_ostream &Out, const ASTContext *Context, const Decl *D,
+ PrintingPolicyModifier PolicyModifier) {
PrintingPolicy Policy = Context->getPrintingPolicy();
Policy.TerseOutput = true;
+ if (PolicyModifier)
+ PolicyModifier(Policy);
D->print(Out, Policy, /*Indentation*/ 0, /*PrintInstantiation*/ false);
}
class PrintMatch : public MatchFinder::MatchCallback {
SmallString<1024> Printed;
unsigned NumFoundDecls;
+ PrintingPolicyModifier PolicyModifier;
public:
- PrintMatch() : NumFoundDecls(0) {}
+ PrintMatch(PrintingPolicyModifier PolicyModifier)
+ : NumFoundDecls(0), PolicyModifier(PolicyModifier) {}
void run(const MatchFinder::MatchResult &Result) override {
const Decl *D = Result.Nodes.getNodeAs<Decl>("id");
@@ -53,7 +60,7 @@
return;
llvm::raw_svector_ostream Out(Printed);
- PrintDecl(Out, Result.Context, D);
+ PrintDecl(Out, Result.Context, D, PolicyModifier);
}
StringRef getPrinted() const {
@@ -65,13 +72,12 @@
}
};
-::testing::AssertionResult PrintedDeclMatches(
- StringRef Code,
- const std::vector<std::string> &Args,
- const DeclarationMatcher &NodeMatch,
- StringRef ExpectedPrinted,
- StringRef FileName) {
- PrintMatch Printer;
+::testing::AssertionResult
+PrintedDeclMatches(StringRef Code, const std::vector<std::string> &Args,
+ const DeclarationMatcher &NodeMatch,
+ StringRef ExpectedPrinted, StringRef FileName,
+ PrintingPolicyModifier PolicyModifier = nullptr) {
+ PrintMatch Printer(PolicyModifier);
MatchFinder Finder;
Finder.addMatcher(NodeMatch, &Printer);
std::unique_ptr<FrontendActionFactory> Factory(
@@ -109,16 +115,17 @@
"input.cc");
}
-::testing::AssertionResult PrintedDeclCXX98Matches(
- StringRef Code,
- const DeclarationMatcher &NodeMatch,
- StringRef ExpectedPrinted) {
+::testing::AssertionResult
+PrintedDeclCXX98Matches(StringRef Code, const DeclarationMatcher &NodeMatch,
+ StringRef ExpectedPrinted,
+ PrintingPolicyModifier PolicyModifier = nullptr) {
std::vector<std::string> Args(1, "-std=c++98");
return PrintedDeclMatches(Code,
Args,
NodeMatch,
ExpectedPrinted,
- "input.cc");
+ "input.cc",
+ PolicyModifier);
}
::testing::AssertionResult PrintedDeclCXX11Matches(StringRef Code,
@@ -478,6 +485,27 @@
"A(const A &a, int = 0)"));
}
+TEST(DeclPrinter, TestCXXConstructorDeclWithMemberInitializer) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct A {"
+ " int m;"
+ " A() : m(2) {}"
+ "};",
+ cxxConstructorDecl(ofClass(hasName("A"))).bind("id"),
+ "A()"));
+}
+
+TEST(DeclPrinter, TestCXXConstructorDeclWithMemberInitializer_NoTerseOutput) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct A {"
+ " int m;"
+ " A() : m(2) {}"
+ "};",
+ cxxConstructorDecl(ofClass(hasName("A"))).bind("id"),
+ "A() : m(2) {\n}\n",
+ [](PrintingPolicy &Policy){ Policy.TerseOutput = false; }));
+}
+
TEST(DeclPrinter, TestCXXConstructorDecl5) {
ASSERT_TRUE(PrintedDeclCXX11Matches(
"struct A {"
@@ -540,7 +568,7 @@
" A(T&&... ts) : T(ts)... {}"
"};",
cxxConstructorDecl(ofClass(hasName("A"))).bind("id"),
- "A<T...>(T &&...ts) : T(ts)... {}"));
+ "A<T...>(T &&...ts)"));
}
TEST(DeclPrinter, TestCXXDestructorDecl1) {

View File

@@ -0,0 +1,33 @@
--- a/tools/clang/test/Index/get-cursor.cpp
+++ b/tools/clang/test/Index/get-cursor.cpp
@@ -152,6 +152,11 @@
void f_dynamic_noexcept() throw(int);
void f_dynamic_noexcept_any() throw(...);
+enum EnumType { Enumerator };
+struct Z {
+ EnumType e = Enumerator;
+};
+
// RUN: c-index-test -cursor-at=%s:6:4 %s | FileCheck -check-prefix=CHECK-COMPLETION-1 %s
// CHECK-COMPLETION-1: CXXConstructor=X:6:3
// CHECK-COMPLETION-1-NEXT: Completion string: {TypedText X}{LeftParen (}{Placeholder int}{Comma , }{Placeholder int}{RightParen )}
@@ -275,3 +280,6 @@
// CHECK-FORRANGE: 141:18 DeclRefExpr=coll:140:20 Extent=[141:18 - 141:22] Spelling=coll ([141:18 - 141:22])
// CHECK-FORRANGE: 142:11 DeclRefExpr=lv:141:13 Extent=[142:11 - 142:13] Spelling=lv ([142:11 - 142:13])
+// RUN: c-index-test -cursor-at=%s:157:18 -std=c++11 %s | FileCheck -check-prefix=CHECK-INCLASSINITIALIZER %s
+// CHECK-INCLASSINITIALIZER: 157:18 DeclRefExpr=Enumerator:155:17 Extent=[157:18 - 157:28] Spelling=Enumerator ([157:18 - 157:28])
+
--- a/tools/clang/tools/libclang/CIndex.cpp
+++ b/tools/clang/tools/libclang/CIndex.cpp
@@ -877,6 +877,9 @@
if (Expr *BitWidth = D->getBitWidth())
return Visit(MakeCXCursor(BitWidth, StmtParent, TU, RegionOfInterest));
+ if (Expr *Init = D->getInClassInitializer())
+ return Visit(MakeCXCursor(Init, StmtParent, TU, RegionOfInterest));
+
return false;
}

View File

@@ -0,0 +1,154 @@
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 3b5ea9fa53..f2397d1b63 100644
--- a/tools/clang/include/clang-c/Index.h
+++ b/tools/clang/include/clang-c/Index.h
@@ -33,6 +33,7 @@
*/
#define CINDEX_VERSION_MAJOR 0
#define CINDEX_VERSION_MINOR 43
+#define CINDEX_VERSION_HAS_ISINVALIDECL_BACKPORTED
#define CINDEX_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \
@@ -2616,6 +2617,16 @@ CINDEX_LINKAGE enum CXCursorKind clang_getCursorKind(CXCursor);
*/
CINDEX_LINKAGE unsigned clang_isDeclaration(enum CXCursorKind);
+/**
+ * \brief Determine whether the given declaration is invalid.
+ *
+ * A declaration is invalid if it could not be parsed successfully.
+ *
+ * \returns non-zero if the cursor represents a declaration and it is
+ * invalid, otherwise NULL.
+ */
+CINDEX_LINKAGE unsigned clang_isInvalidDeclaration(CXCursor);
+
/**
* \brief Determine whether the given cursor kind represents a simple
* reference.
diff --git a/test/Index/opencl-types.cl b/test/Index/opencl-types.cl
index fe0042aa20..d71893a220 100644
--- a/tools/clang/test/Index/opencl-types.cl
+++ b/tools/clang/test/Index/opencl-types.cl
@@ -16,11 +16,11 @@ void kernel testFloatTypes() {
double4 vectorDouble;
}
-// CHECK: VarDecl=scalarHalf:11:8 (Definition) [type=half] [typekind=Half] [isPOD=1]
+// CHECK: VarDecl=scalarHalf:11:8 (Definition){{( \(invalid\))?}} [type=half] [typekind=Half] [isPOD=1]
// CHECK: VarDecl=vectorHalf:12:9 (Definition) [type=half4] [typekind=Typedef] [canonicaltype=half __attribute__((ext_vector_type(4)))] [canonicaltypekind=Unexposed] [isPOD=1]
// CHECK: VarDecl=scalarFloat:13:9 (Definition) [type=float] [typekind=Float] [isPOD=1]
// CHECK: VarDecl=vectorFloat:14:10 (Definition) [type=float4] [typekind=Typedef] [canonicaltype=float __attribute__((ext_vector_type(4)))] [canonicaltypekind=Unexposed] [isPOD=1]
-// CHECK: VarDecl=scalarDouble:15:10 (Definition) [type=double] [typekind=Double] [isPOD=1]
+// CHECK: VarDecl=scalarDouble:15:10 (Definition){{( \(invalid\))?}} [type=double] [typekind=Double] [isPOD=1]
// CHECK: VarDecl=vectorDouble:16:11 (Definition) [type=double4] [typekind=Typedef] [canonicaltype=double __attribute__((ext_vector_type(4)))] [canonicaltypekind=Unexposed] [isPOD=1]
#pragma OPENCL EXTENSION cl_khr_gl_msaa_sharing : enable
@@ -45,10 +45,10 @@ void kernel OCLImage3dROTest(read_only image3d_t scalarOCLImage3dRO);
// CHECK: ParmDecl=scalarOCLImage2dArrayRO:32:61 (Definition) [type=__read_only image2d_array_t] [typekind=OCLImage2dArrayRO] [isPOD=1]
// CHECK: ParmDecl=scalarOCLImage2dDepthRO:33:61 (Definition) [type=__read_only image2d_depth_t] [typekind=OCLImage2dDepthRO] [isPOD=1]
// CHECK: ParmDecl=scalarOCLImage2dArrayDepthRO:34:72 (Definition) [type=__read_only image2d_array_depth_t] [typekind=OCLImage2dArrayDepthRO] [isPOD=1]
-// CHECK: ParmDecl=scalarOCLImage2dMSAARO:35:59 (Definition) [type=__read_only image2d_msaa_t] [typekind=OCLImage2dMSAARO] [isPOD=1]
-// CHECK: ParmDecl=scalarOCLImage2dArrayMSAARO:36:70 (Definition) [type=__read_only image2d_array_msaa_t] [typekind=OCLImage2dArrayMSAARO] [isPOD=1]
-// CHECK: ParmDecl=scalarOCLImage2dMSAADepthRO:37:70 (Definition) [type=__read_only image2d_msaa_depth_t] [typekind=OCLImage2dMSAADepthRO] [isPOD=1]
-// CHECK: ParmDecl=scalarOCLImage2dArrayMSAADepthRO:38:81 (Definition) [type=__read_only image2d_array_msaa_depth_t] [typekind=OCLImage2dArrayMSAADepthRO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dMSAARO:35:59 (Definition){{( \(invalid\))?}} [type=__read_only image2d_msaa_t] [typekind=OCLImage2dMSAARO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayMSAARO:36:70 (Definition){{( \(invalid\))?}} [type=__read_only image2d_array_msaa_t] [typekind=OCLImage2dArrayMSAARO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dMSAADepthRO:37:70 (Definition){{( \(invalid\))?}} [type=__read_only image2d_msaa_depth_t] [typekind=OCLImage2dMSAADepthRO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayMSAADepthRO:38:81 (Definition){{( \(invalid\))?}} [type=__read_only image2d_array_msaa_depth_t] [typekind=OCLImage2dArrayMSAADepthRO] [isPOD=1]
// CHECK: ParmDecl=scalarOCLImage3dRO:39:50 (Definition) [type=__read_only image3d_t] [typekind=OCLImage3dRO] [isPOD=1]
void kernel OCLImage1dWOTest(write_only image1d_t scalarOCLImage1dWO);
@@ -71,11 +71,11 @@ void kernel OCLImage3dWOTest(write_only image3d_t scalarOCLImage3dWO);
// CHECK: ParmDecl=scalarOCLImage2dArrayWO:58:62 (Definition) [type=__write_only image2d_array_t] [typekind=OCLImage2dArrayWO] [isPOD=1]
// CHECK: ParmDecl=scalarOCLImage2dDepthWO:59:62 (Definition) [type=__write_only image2d_depth_t] [typekind=OCLImage2dDepthWO] [isPOD=1]
// CHECK: ParmDecl=scalarOCLImage2dArrayDepthWO:60:73 (Definition) [type=__write_only image2d_array_depth_t] [typekind=OCLImage2dArrayDepthWO] [isPOD=1]
-// CHECK: ParmDecl=scalarOCLImage2dMSAAWO:61:60 (Definition) [type=__write_only image2d_msaa_t] [typekind=OCLImage2dMSAAWO] [isPOD=1]
-// CHECK: ParmDecl=scalarOCLImage2dArrayMSAAWO:62:71 (Definition) [type=__write_only image2d_array_msaa_t] [typekind=OCLImage2dArrayMSAAWO] [isPOD=1]
-// CHECK: ParmDecl=scalarOCLImage2dMSAADepthWO:63:71 (Definition) [type=__write_only image2d_msaa_depth_t] [typekind=OCLImage2dMSAADepthWO] [isPOD=1]
-// CHECK: ParmDecl=scalarOCLImage2dArrayMSAADepthWO:64:82 (Definition) [type=__write_only image2d_array_msaa_depth_t] [typekind=OCLImage2dArrayMSAADepthWO] [isPOD=1]
-// CHECK: ParmDecl=scalarOCLImage3dWO:65:51 (Definition) [type=__write_only image3d_t] [typekind=OCLImage3dWO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dMSAAWO:61:60 (Definition){{( \(invalid\))?}} [type=__write_only image2d_msaa_t] [typekind=OCLImage2dMSAAWO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayMSAAWO:62:71 (Definition){{( \(invalid\))?}} [type=__write_only image2d_array_msaa_t] [typekind=OCLImage2dArrayMSAAWO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dMSAADepthWO:63:71 (Definition){{( \(invalid\))?}} [type=__write_only image2d_msaa_depth_t] [typekind=OCLImage2dMSAADepthWO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayMSAADepthWO:64:82 (Definition){{( \(invalid\))?}} [type=__write_only image2d_array_msaa_depth_t] [typekind=OCLImage2dArrayMSAADepthWO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage3dWO:65:51 (Definition){{( \(invalid\))?}} [type=__write_only image3d_t] [typekind=OCLImage3dWO] [isPOD=1]
void kernel OCLImage1dRWTest(read_write image1d_t scalarOCLImage1dRW);
void kernel OCLImage1dArrayRWTest(read_write image1d_array_t scalarOCLImage1dArrayRW);
@@ -97,10 +97,10 @@ void kernel OCLImage3dRWTest(read_write image3d_t scalarOCLImage3dRW);
// CHECK: ParmDecl=scalarOCLImage2dArrayRW:84:62 (Definition) [type=__read_write image2d_array_t] [typekind=OCLImage2dArrayRW] [isPOD=1]
// CHECK: ParmDecl=scalarOCLImage2dDepthRW:85:62 (Definition) [type=__read_write image2d_depth_t] [typekind=OCLImage2dDepthRW] [isPOD=1]
// CHECK: ParmDecl=scalarOCLImage2dArrayDepthRW:86:73 (Definition) [type=__read_write image2d_array_depth_t] [typekind=OCLImage2dArrayDepthRW] [isPOD=1]
-// CHECK: ParmDecl=scalarOCLImage2dMSAARW:87:60 (Definition) [type=__read_write image2d_msaa_t] [typekind=OCLImage2dMSAARW] [isPOD=1]
-// CHECK: ParmDecl=scalarOCLImage2dArrayMSAARW:88:71 (Definition) [type=__read_write image2d_array_msaa_t] [typekind=OCLImage2dArrayMSAARW] [isPOD=1]
-// CHECK: ParmDecl=scalarOCLImage2dMSAADepthRW:89:71 (Definition) [type=__read_write image2d_msaa_depth_t] [typekind=OCLImage2dMSAADepthRW] [isPOD=1]
-// CHECK: ParmDecl=scalarOCLImage2dArrayMSAADepthRW:90:82 (Definition) [type=__read_write image2d_array_msaa_depth_t] [typekind=OCLImage2dArrayMSAADepthRW] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dMSAARW:87:60 (Definition){{( \(invalid\))?}} [type=__read_write image2d_msaa_t] [typekind=OCLImage2dMSAARW] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayMSAARW:88:71 (Definition){{( \(invalid\))?}} [type=__read_write image2d_array_msaa_t] [typekind=OCLImage2dArrayMSAARW] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dMSAADepthRW:89:71 (Definition){{( \(invalid\))?}} [type=__read_write image2d_msaa_depth_t] [typekind=OCLImage2dMSAADepthRW] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayMSAADepthRW:90:82 (Definition){{( \(invalid\))?}} [type=__read_write image2d_array_msaa_depth_t] [typekind=OCLImage2dArrayMSAADepthRW] [isPOD=1]
// CHECK: ParmDecl=scalarOCLImage3dRW:91:51 (Definition) [type=__read_write image3d_t] [typekind=OCLImage3dRW] [isPOD=1]
void kernel intPipeTestRO(read_only pipe int scalarPipe);
diff --git a/test/Index/print-type-size.cpp b/test/Index/print-type-size.cpp
index 45de93f308..1ea5346273 100644
--- a/tools/clang/test/Index/print-type-size.cpp
+++ b/tools/clang/test/Index/print-type-size.cpp
@@ -4,8 +4,8 @@
namespace basic {
-// CHECK64: VarDecl=v:[[@LINE+2]]:6 (Definition) [type=void] [typekind=Void]
-// CHECK32: VarDecl=v:[[@LINE+1]]:6 (Definition) [type=void] [typekind=Void]
+// CHECK64: VarDecl=v:[[@LINE+2]]:6 (Definition) (invalid) [type=void] [typekind=Void]
+// CHECK32: VarDecl=v:[[@LINE+1]]:6 (Definition) (invalid) [type=void] [typekind=Void]
void v;
// CHECK64: VarDecl=v1:[[@LINE+2]]:7 (Definition) [type=void *] [typekind=Pointer] [sizeof=8] [alignof=8]
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index cf3581e259..759ed449a4 100644
--- a/tools/clang/tools/c-index-test/c-index-test.c
+++ b/tools/clang/tools/c-index-test/c-index-test.c
@@ -810,6 +810,8 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
printf(" (variadic)");
if (clang_Cursor_isObjCOptional(Cursor))
printf(" (@optional)");
+ if (clang_isInvalidDeclaration(Cursor))
+ printf(" (invalid)");
switch (clang_getCursorExceptionSpecificationType(Cursor))
{
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 9ba4d5bf30..584de42e7c 100644
--- a/tools/clang/tools/libclang/CIndex.cpp
+++ b/tools/clang/tools/libclang/CIndex.cpp
@@ -5346,6 +5346,15 @@ unsigned clang_isDeclaration(enum CXCursorKind K) {
(K >= CXCursor_FirstExtraDecl && K <= CXCursor_LastExtraDecl);
}
+unsigned clang_isInvalidDeclaration(CXCursor C) {
+ if (clang_isDeclaration(C.kind)) {
+ if (const Decl *D = getCursorDecl(C))
+ return D->isInvalidDecl();
+ }
+
+ return 0;
+}
+
unsigned clang_isReference(enum CXCursorKind K) {
return K >= CXCursor_FirstRef && K <= CXCursor_LastRef;
}
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index e0d178a529..7192baab6a 100644
--- a/tools/clang/tools/libclang/libclang.exports
+++ b/tools/clang/tools/libclang/libclang.exports
@@ -286,6 +286,7 @@ clang_isAttribute
clang_isConstQualifiedType
clang_isCursorDefinition
clang_isDeclaration
+clang_isInvalidDeclaration
clang_isExpression
clang_isFileMultipleIncludeGuarded
clang_isFunctionTypeVariadic

View File

@@ -0,0 +1,79 @@
--- a/tools/clang/test/Index/annotate-tokens.cpp
+++ b/tools/clang/test/Index/annotate-tokens.cpp
@@ -37,7 +37,9 @@ class C {
~C();
};
-// RUN: c-index-test -test-annotate-tokens=%s:1:1:38:1 %s -fno-delayed-template-parsing | FileCheck %s
+auto test5(X) -> X;
+
+// RUN: c-index-test -test-annotate-tokens=%s:1:1:41:1 %s -std=c++14 -fno-delayed-template-parsing | FileCheck %s
// CHECK: Keyword: "struct" [1:1 - 1:7] StructDecl=bonk:1:8 (Definition)
// CHECK: Identifier: "bonk" [1:8 - 1:12] StructDecl=bonk:1:8 (Definition)
// CHECK: Punctuation: "{" [1:13 - 1:14] StructDecl=bonk:1:8 (Definition)
@@ -184,6 +186,14 @@ class C {
// CHECK: Punctuation: "}" [29:22 - 29:23] CompoundStmt=
// CHECK: Punctuation: "~" [37:3 - 37:4] CXXDestructor=~C:37:3
// CHECK: Identifier: "C" [37:4 - 37:5] CXXDestructor=~C:37:3
+// CHECK: Keyword: "auto" [40:1 - 40:5] FunctionDecl=test5:40:6
+// CHECK: Identifier: "test5" [40:6 - 40:11] FunctionDecl=test5:40:6
+// CHECK: Punctuation: "(" [40:11 - 40:12] FunctionDecl=test5:40:6
+// CHECK: Identifier: "X" [40:12 - 40:13] TypeRef=struct X:7:8
+// CHECK: Punctuation: ")" [40:13 - 40:14] FunctionDecl=test5:40:6
+// CHECK: Punctuation: "->" [40:15 - 40:17] FunctionDecl=test5:40:6
+// CHECK: Identifier: "X" [40:18 - 40:19] TypeRef=struct X:7:8
+// CHECK: Punctuation: ";" [40:19 - 40:20]
// RUN: env LIBCLANG_DISABLE_CRASH_RECOVERY=1 c-index-test -test-annotate-tokens=%s:32:1:32:13 %s | FileCheck %s -check-prefix=CHECK2
// CHECK2: Keyword: "if" [32:3 - 32:5] IfStmt=
--- a/tools/clang/tools/libclang/CIndex.cpp
+++ b/tools/clang/tools/libclang/CIndex.cpp
@@ -783,6 +783,16 @@ bool CursorVisitor::VisitDeclaratorDecl(DeclaratorDecl *DD) {
return false;
}
+static bool HasTrailingReturnType(FunctionDecl *ND) {
+ const QualType Ty = ND->getType();
+ if (const FunctionType *AFT = Ty->getAs<FunctionType>()) {
+ if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(AFT))
+ return FT->hasTrailingReturn();
+ }
+
+ return false;
+}
+
/// \brief Compare two base or member initializers based on their source order.
static int CompareCXXCtorInitializers(CXXCtorInitializer *const *X,
CXXCtorInitializer *const *Y) {
@@ -802,14 +812,16 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
// written. This requires a bit of work.
TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();
FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>();
+ const bool HasTrailingRT = HasTrailingReturnType(ND);
// If we have a function declared directly (without the use of a typedef),
// visit just the return type. Otherwise, just visit the function's type
// now.
- if ((FTL && !isa<CXXConversionDecl>(ND) && Visit(FTL.getReturnLoc())) ||
+ if ((FTL && !isa<CXXConversionDecl>(ND) && !HasTrailingRT &&
+ Visit(FTL.getReturnLoc())) ||
(!FTL && Visit(TL)))
return true;
-
+
// Visit the nested-name-specifier, if present.
if (NestedNameSpecifierLoc QualifierLoc = ND->getQualifierLoc())
if (VisitNestedNameSpecifierLoc(QualifierLoc))
@@ -825,7 +837,11 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
// Visit the function parameters, if we have a function type.
if (FTL && VisitFunctionTypeLoc(FTL, true))
return true;
-
+
+ // Visit the function's trailing return type.
+ if (FTL && HasTrailingRT && Visit(FTL.getReturnLoc()))
+ return true;
+
// FIXME: Attributes?
}

View File

@@ -0,0 +1,78 @@
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index f2397d1b63..0f4ade266c 100644
--- a/tools/clang/include/clang-c/Index.h
+++ b/tools/clang/include/clang-c/Index.h
@@ -34,6 +34,7 @@
#define CINDEX_VERSION_MAJOR 0
#define CINDEX_VERSION_MINOR 43
#define CINDEX_VERSION_HAS_ISINVALIDECL_BACKPORTED
+#define CINDEX_VERSION_HAS_GETFILECONTENTS_BACKPORTED
#define CINDEX_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \
@@ -394,6 +395,21 @@ clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, CXFile file);
CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu,
const char *file_name);
+/**
+ * \brief Retrieve the buffer associated with the given file.
+ *
+ * \param tu the translation unit
+ *
+ * \param file the file for which to retrieve the buffer.
+ *
+ * \param size [out] if non-NULL, will be set to the size of the buffer.
+ *
+ * \returns a pointer to the buffer in memory that holds the contents of
+ * \p file, or a NULL pointer when the file is not loaded.
+ */
+CINDEX_LINKAGE const char *clang_getFileContents(CXTranslationUnit tu,
+ CXFile file, size_t *size);
+
/**
* \brief Returns non-zero if the \c file1 and \c file2 point to the same file,
* or they are both NULL.
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 13599e1910..7902e8a030 100644
--- a/tools/clang/tools/libclang/CIndex.cpp
+++ b/tools/clang/tools/libclang/CIndex.cpp
@@ -4148,6 +4148,27 @@ CXFile clang_getFile(CXTranslationUnit TU, const char *file_name) {
return const_cast<FileEntry *>(FMgr.getFile(file_name));
}
+const char *clang_getFileContents(CXTranslationUnit TU, CXFile file,
+ size_t *size) {
+ if (isNotUsableTU(TU)) {
+ LOG_BAD_TU(TU);
+ return nullptr;
+ }
+
+ const SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager();
+ FileID fid = SM.translateFile(static_cast<FileEntry *>(file));
+ bool Invalid = true;
+ llvm::MemoryBuffer *buf = SM.getBuffer(fid, &Invalid);
+ if (Invalid) {
+ if (size)
+ *size = 0;
+ return nullptr;
+ }
+ if (size)
+ *size = buf->getBufferSize();
+ return buf->getBufferStart();
+}
+
unsigned clang_isFileMultipleIncludeGuarded(CXTranslationUnit TU,
CXFile file) {
if (isNotUsableTU(TU)) {
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 7192baab6a..c788abb881 100644
--- a/tools/clang/tools/libclang/libclang.exports
+++ b/tools/clang/tools/libclang/libclang.exports
@@ -216,6 +216,7 @@ clang_getExceptionSpecificationType
clang_getFieldDeclBitWidth
clang_getExpansionLocation
clang_getFile
+clang_getFileContents
clang_getFileLocation
clang_getFileName
clang_getFileTime

View File

@@ -0,0 +1,47 @@
--- a/tools/clang/lib/Serialization/ASTReader.cpp
+++ b/tools/clang/lib/Serialization/ASTReader.cpp
@@ -1220,6 +1220,7 @@
// Parse the file names
std::map<int, int> FileIDs;
+ FileIDs[-1] = -1; // For unspecified filenames.
for (unsigned I = 0; Record[Idx]; ++I) {
// Extract the file name
auto Filename = ReadPath(F, Record, Idx);
--- a/tools/clang/lib/Serialization/ASTWriter.cpp
+++ b/tools/clang/lib/Serialization/ASTWriter.cpp
@@ -2363,12 +2363,13 @@
// Emit the needed file names.
llvm::DenseMap<int, int> FilenameMap;
+ FilenameMap[-1] = -1; // For unspecified filenames.
for (const auto &L : LineTable) {
if (L.first.ID < 0)
continue;
for (auto &LE : L.second) {
if (FilenameMap.insert(std::make_pair(LE.FilenameID,
- FilenameMap.size())).second)
+ FilenameMap.size() - 1)).second)
AddPath(LineTable.getFilename(LE.FilenameID), Record);
}
}
--- a/tools/clang/test/PCH/line-directive-nofilename.h
+++ b/tools/clang/test/PCH/line-directive-nofilename.h
@@ -0,0 +1,5 @@
+#line 42
+int foo; // This should appear as at line-directive-nofilename.h:42
+
+#line 100 "foobar.h"
+int bar; // This should appear as at foobar.h:100
--- a/tools/clang/test/PCH/line-directive-nofilename.c
+++ b/tools/clang/test/PCH/line-directive-nofilename.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-pch -o %t %S/line-directive-nofilename.h
+// RUN: not %clang_cc1 -include-pch %t -fsyntax-only %s 2>&1 | FileCheck %s
+
+// This causes an "error: redefinition" diagnostic. The notes will have the
+// locations of the declarations from the PCH file.
+double foo, bar;
+
+// CHECK: line-directive-nofilename.h:42:5: note: previous definition is here
+// CHECK: foobar.h:100:5: note: previous definition is here

View File

@@ -0,0 +1,117 @@
--- a/tools/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/tools/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -22,6 +22,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/ParentMap.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/Builtins.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -262,8 +263,19 @@
if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) {
// We just finished a base constructor. Now we can use the subclass's
// type when resolving virtual calls.
- const Decl *D = C.getLocationContext()->getDecl();
- recordFixedType(Target, cast<CXXConstructorDecl>(D), C);
+ const LocationContext *LCtx = C.getLocationContext();
+
+ // FIXME: In C++17 classes with non-virtual bases may be treated as
+ // aggregates, and in such case no top-frame constructor will be called.
+ // Figure out if we need to do anything in this case.
+ // FIXME: Instead of relying on the ParentMap, we should have the
+ // trigger-statement (InitListExpr in this case) available in this
+ // callback, ideally as part of CallEvent.
+ if (dyn_cast_or_null<InitListExpr>(
+ LCtx->getParentMap().getParent(Ctor->getOriginExpr())))
+ return;
+
+ recordFixedType(Target, cast<CXXConstructorDecl>(LCtx->getDecl()), C);
}
return;
}
--- a/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -14,6 +14,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/ParentMap.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
@@ -267,6 +268,23 @@
}
// FALLTHROUGH
case CXXConstructExpr::CK_NonVirtualBase:
+ // In C++17, classes with non-virtual bases may be aggregates, so they would
+ // be initialized as aggregates without a constructor call, so we may have
+ // a base class constructed directly into an initializer list without
+ // having the derived-class constructor call on the previous stack frame.
+ // Initializer lists may be nested into more initializer lists that
+ // correspond to surrounding aggregate initializations.
+ // FIXME: For now this code essentially bails out. We need to find the
+ // correct target region and set it.
+ // FIXME: Instead of relying on the ParentMap, we should have the
+ // trigger-statement (InitListExpr in this case) passed down from CFG or
+ // otherwise always available during construction.
+ if (dyn_cast_or_null<InitListExpr>(LCtx->getParentMap().getParent(CE))) {
+ MemRegionManager &MRMgr = getSValBuilder().getRegionManager();
+ Target = MRMgr.getCXXTempObjectRegion(CE, LCtx);
+ break;
+ }
+ // FALLTHROUGH
case CXXConstructExpr::CK_Delegating: {
const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor,
--- a/tools/clang/test/Analysis/initializer.cpp
+++ a/tools/clang/test/Analysis/initializer.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=constructors -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,cplusplus.NewDeleteLeaks,debug.ExprInspection -analyzer-config c++-inlining=constructors -std=c++17 -DCPLUSPLUS17 -verify %s
void clang_analyzer_eval(bool);
@@ -224,3 +225,42 @@
const char(&f)[2];
};
}
+
+namespace CXX17_aggregate_construction {
+struct A {
+ A();
+};
+
+struct B: public A {
+};
+
+struct C: public B {
+};
+
+struct D: public virtual A {
+};
+
+// In C++17, classes B and C are aggregates, so they will be constructed
+// without actually calling their trivial constructor. Used to crash.
+void foo() {
+ B b = {}; // no-crash
+ const B &bl = {}; // no-crash
+ B &&br = {}; // no-crash
+
+ C c = {}; // no-crash
+ const C &cl = {}; // no-crash
+ C &&cr = {}; // no-crash
+
+ D d = {}; // no-crash
+
+#ifdef CPLUSPLUS17
+ C cd = {{}}; // no-crash
+ const C &cdl = {{}}; // no-crash
+ C &&cdr = {{}}; // no-crash
+
+ const B &bll = {{}}; // no-crash
+ const B &bcl = C({{}}); // no-crash
+ B &&bcr = C({{}}); // no-crash
+#endif
+}
+}

View File

@@ -0,0 +1,37 @@
--- a/tools/clang/include/clang/Sema/ScopeInfo.h
+++ b/tools/clang/include/clang/Sema/ScopeInfo.h
@@ -560,6 +560,7 @@
void markUsed(bool IsODRUse) { (IsODRUse ? ODRUsed : NonODRUsed) = true; }
VarDecl *getVariable() const {
+ assert(isVariableCapture());
return VarAndNestedAndThis.getPointer();
}
--- a/tools/clang/lib/Sema/SemaLambda.cpp
+++ b/tools/clang/lib/Sema/SemaLambda.cpp
@@ -1481,6 +1481,9 @@
if (CaptureHasSideEffects(From))
return;
+ if (From.isVLATypeCapture())
+ return;
+
auto diag = Diag(From.getLocation(), diag::warn_unused_lambda_capture);
if (From.isThisCapture())
diag << "'this'";
--- a/tools/clang/test/SemaCXX/warn-unused-lambda-capture.cpp
+++ b/tools/clang/test/SemaCXX/warn-unused-lambda-capture.cpp
@@ -191,3 +191,12 @@
void test_use_template() {
test_templated<int>(); // expected-note{{in instantiation of function template specialization 'test_templated<int>' requested here}}
}
+
+namespace pr35555 {
+int a;
+void b() {
+ int c[a];
+ auto vla_used = [&c] { return c[0]; };
+ auto vla_unused = [&c] {}; // expected-warning{{lambda capture 'c' is not used}}
+}
+} // namespace pr35555

View File

@@ -0,0 +1,47 @@
--- a/tools/clang/lib/Lex/PPCaching.cpp
+++ b/tools/clang/lib/Lex/PPCaching.cpp
@@ -105,8 +105,10 @@
}
void Preprocessor::EnterCachingLexMode() {
- if (InCachingLexMode())
+ if (InCachingLexMode()) {
+ assert(CurLexerKind == CLK_CachingLexer && "Unexpected lexer kind");
return;
+ }
PushIncludeMacroStack();
CurLexerKind = CLK_CachingLexer;
--- a/tools/clang/lib/Lex/PPLexerChange.cpp
+++ b/tools/clang/lib/Lex/PPLexerChange.cpp
@@ -444,6 +444,7 @@
}
CurPPLexer = nullptr;
+ recomputeCurLexerKind();
return true;
}
--- /dev/null
+++ b/tools/clang/test/CodeCompletion/Inputs/comments.h
@@ -0,0 +1,4 @@
+// PR32732
+struct B {
+ // <- code completion
+};
--- /dev/null
+++ b/tools/clang/test/CodeCompletion/comments.cpp
@@ -0,0 +1,13 @@
+// Note: the run lines follow their respective tests, since line/column
+// matter in this test.
+
+#include "comments.h"
+
+struct A {
+ // <- code completion
+ /* <- code completion */
+};
+
+// RUN: %clang_cc1 -I %S/Inputs -fsyntax-only -code-completion-at=%s:7:6 %s
+// RUN: %clang_cc1 -I %S/Inputs -fsyntax-only -code-completion-at=%s:8:6 %s
+// RUN: %clang_cc1 -I %S/Inputs -fsyntax-only -code-completion-at=%S/Inputs/comments.h:3:6 %s

View File

@@ -20,6 +20,6 @@ index 4440637820..6798d2ee8b 100644
list(APPEND LIBS clangTidyPlugin)
list(APPEND LIBS clangIncludeFixerPlugin)
+ list(APPEND LIBS clazyPlugin)
if(LLVM_ENABLE_MODULES)
list(APPEND LLVM_COMPILE_FLAGS "-fmodules-ignore-macro=CLANG_TOOL_EXTRA_BUILD")
endif()
endif ()
find_library(DL_LIBRARY_PATH dl)

View File

@@ -0,0 +1,144 @@
From 363747b90f66f097fd45a6cd665adbaf7612188a Mon Sep 17 00:00:00 2001
From: Nikolai Kosjar <nikolai.kosjar@qt.io>
Date: Mon, 15 Jan 2018 12:51:18 +0100
Subject: [PATCH 2/3] Backport: [DeclPrinter] Allow printing fully qualified
name of function declaration
https://reviews.llvm.org/D40013
---
include/clang/AST/PrettyPrinter.h | 7 +++++-
lib/AST/DeclPrinter.cpp | 16 ++++++++----
unittests/AST/DeclPrinterTest.cpp | 51 ++++++++++++++++++++++++++++++++++++---
3 files changed, 64 insertions(+), 10 deletions(-)
diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h
index 274df220e1..edcef0ae24 100644
--- a/tools/clang/include/clang/AST/PrettyPrinter.h
+++ b/tools/clang/include/clang/AST/PrettyPrinter.h
@@ -50,7 +50,8 @@ struct PrintingPolicy {
UseVoidForZeroParams(!LO.CPlusPlus),
TerseOutput(false), PolishForDeclaration(false),
Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar),
- IncludeNewlines(true), MSVCFormatting(false) { }
+ IncludeNewlines(true), MSVCFormatting(false),
+ FullyQualifiedName(false) { }
/// \brief Adjust this printing policy for cases where it's known that
/// we're printing C++ code (for instance, if AST dumping reaches a
@@ -200,6 +201,10 @@ struct PrintingPolicy {
/// prints anonymous namespaces as `anonymous namespace' and does not insert
/// spaces after template arguments.
bool MSVCFormatting : 1;
+
+ /// When true, print the fully qualified name of function declarations.
+ /// This is the opposite of SuppressScope and thus overrules it.
+ bool FullyQualifiedName : 1;
};
} // end namespace clang
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 37f08a4985..ea37abe8f6 100644
--- a/tools/clang/lib/AST/DeclPrinter.cpp
+++ b/tools/clang/lib/AST/DeclPrinter.cpp
@@ -510,13 +510,19 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
PrintingPolicy SubPolicy(Policy);
SubPolicy.SuppressSpecifiers = false;
std::string Proto;
- if (!Policy.SuppressScope) {
- if (const NestedNameSpecifier *NS = D->getQualifier()) {
- llvm::raw_string_ostream OS(Proto);
- NS->print(OS, Policy);
+
+ if (Policy.FullyQualifiedName) {
+ Proto += D->getQualifiedNameAsString();
+ } else {
+ if (!Policy.SuppressScope) {
+ if (const NestedNameSpecifier *NS = D->getQualifier()) {
+ llvm::raw_string_ostream OS(Proto);
+ NS->print(OS, Policy);
+ }
}
+ Proto += D->getNameInfo().getAsString();
}
- Proto += D->getNameInfo().getAsString();
+
if (GuideDecl)
Proto = GuideDecl->getDeducedTemplate()->getDeclName().getAsString();
if (const TemplateArgumentList *TArgs = D->getTemplateSpecializationArgs()) {
diff --git a/unittests/AST/DeclPrinterTest.cpp b/unittests/AST/DeclPrinterTest.cpp
index dc1977d876..4cf8bce20e 100644
--- a/tools/clang/unittests/AST/DeclPrinterTest.cpp
+++ b/tools/clang/unittests/AST/DeclPrinterTest.cpp
@@ -104,15 +104,17 @@ PrintedDeclMatches(StringRef Code, const std::vector<std::string> &Args,
return ::testing::AssertionSuccess();
}
-::testing::AssertionResult PrintedDeclCXX98Matches(StringRef Code,
- StringRef DeclName,
- StringRef ExpectedPrinted) {
+::testing::AssertionResult
+PrintedDeclCXX98Matches(StringRef Code, StringRef DeclName,
+ StringRef ExpectedPrinted,
+ PrintingPolicyModifier PolicyModifier = nullptr) {
std::vector<std::string> Args(1, "-std=c++98");
return PrintedDeclMatches(Code,
Args,
namedDecl(hasName(DeclName)).bind("id"),
ExpectedPrinted,
- "input.cc");
+ "input.cc",
+ PolicyModifier);
}
::testing::AssertionResult
@@ -350,6 +352,47 @@ TEST(DeclPrinter, TestFunctionDecl1) {
"void A()"));
}
+TEST(DeclPrinter, TestFreeFunctionDecl_FullyQualifiedName) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "void A();",
+ "A",
+ "void A()",
+ [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; }));
+}
+
+TEST(DeclPrinter, TestFreeFunctionDeclInNamespace_FullyQualifiedName) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "namespace X { void A(); };",
+ "A",
+ "void X::A()",
+ [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; }));
+}
+
+TEST(DeclPrinter, TestMemberFunction_FullyQualifiedName) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct X { void A(); };",
+ "A",
+ "void X::A()",
+ [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; }));
+}
+
+TEST(DeclPrinter, TestMemberFunctionInNamespace_FullyQualifiedName) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "namespace Z { struct X { void A(); }; }",
+ "A",
+ "void Z::X::A()",
+ [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; }));
+}
+
+TEST(DeclPrinter, TestMemberFunctionOutside_FullyQualifiedName) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct X { void A(); };"
+ "void X::A() {}",
+ functionDecl(hasName("A"), isDefinition()).bind("id"),
+ "void X::A()",
+ [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; }));
+}
+
TEST(DeclPrinter, TestFunctionDecl2) {
ASSERT_TRUE(PrintedDeclCXX98Matches(
"void A() {}",
--
2.15.1

View File

@@ -0,0 +1,544 @@
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 0f4ade266c..f188ec9d8c 100644
--- a/tools/clang/include/clang-c/Index.h
+++ b/tools/clang/include/clang-c/Index.h
@@ -35,6 +35,7 @@
#define CINDEX_VERSION_MINOR 43
#define CINDEX_VERSION_HAS_ISINVALIDECL_BACKPORTED
#define CINDEX_VERSION_HAS_GETFILECONTENTS_BACKPORTED
+#define CINDEX_VERSION_HAS_PRETTYDECL_BACKPORTED
#define CINDEX_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \
@@ -4066,6 +4067,90 @@ CINDEX_LINKAGE CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor,
unsigned pieceIndex,
unsigned options);
+/**
+ * \brief Opaque pointer representing a policy that controls pretty printing
+ * for \c clang_getCursorPrettyPrinted.
+ */
+typedef void *CXPrintingPolicy;
+
+/**
+ * \brief Properties for the printing policy.
+ *
+ * See \c clang::PrintingPolicy for more information.
+ */
+enum CXPrintingPolicyProperty {
+ CXPrintingPolicy_Indentation,
+ CXPrintingPolicy_SuppressSpecifiers,
+ CXPrintingPolicy_SuppressTagKeyword,
+ CXPrintingPolicy_IncludeTagDefinition,
+ CXPrintingPolicy_SuppressScope,
+ CXPrintingPolicy_SuppressUnwrittenScope,
+ CXPrintingPolicy_SuppressInitializers,
+ CXPrintingPolicy_ConstantArraySizeAsWritten,
+ CXPrintingPolicy_AnonymousTagLocations,
+ CXPrintingPolicy_SuppressStrongLifetime,
+ CXPrintingPolicy_SuppressLifetimeQualifiers,
+ CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors,
+ CXPrintingPolicy_Bool,
+ CXPrintingPolicy_Restrict,
+ CXPrintingPolicy_Alignof,
+ CXPrintingPolicy_UnderscoreAlignof,
+ CXPrintingPolicy_UseVoidForZeroParams,
+ CXPrintingPolicy_TerseOutput,
+ CXPrintingPolicy_PolishForDeclaration,
+ CXPrintingPolicy_Half,
+ CXPrintingPolicy_MSWChar,
+ CXPrintingPolicy_IncludeNewlines,
+ CXPrintingPolicy_MSVCFormatting,
+ CXPrintingPolicy_ConstantsAsWritten, /* Ops, not yet there in clang 5.0 and we do not need it. */
+ CXPrintingPolicy_SuppressImplicitBase, /* Ops, not yet there in clang 5.0 and we do not need it. */
+ CXPrintingPolicy_FullyQualifiedName,
+
+ CXPrintingPolicy_LastProperty = CXPrintingPolicy_FullyQualifiedName
+};
+
+/**
+ * \brief Get a property value for the given printing policy.
+ */
+CINDEX_LINKAGE unsigned
+clang_PrintingPolicy_getProperty(CXPrintingPolicy Policy,
+ enum CXPrintingPolicyProperty Property);
+
+/**
+ * \brief Set a property value for the given printing policy.
+ */
+CINDEX_LINKAGE void
+clang_PrintingPolicy_setProperty(CXPrintingPolicy Policy,
+ enum CXPrintingPolicyProperty Property,
+ unsigned Value);
+
+/**
+ * \brief Retrieve the default policy for the cursor.
+ *
+ * The policy should be released after use with \c
+ * clang_PrintingPolicy_dispose.
+ */
+CINDEX_LINKAGE CXPrintingPolicy clang_getCursorPrintingPolicy(CXCursor);
+
+/**
+ * \brief Release a printing policy.
+ */
+CINDEX_LINKAGE void clang_PrintingPolicy_dispose(CXPrintingPolicy Policy);
+
+/**
+ * \brief Pretty print declarations.
+ *
+ * \param Cursor The cursor representing a declaration.
+ *
+ * \param Policy The policy to control the entities being printed. If
+ * NULL, a default policy is used.
+ *
+ * \returns The pretty printed declaration or the empty string for
+ * other cursors.
+ */
+CINDEX_LINKAGE CXString clang_getCursorPrettyPrinted(CXCursor Cursor,
+ CXPrintingPolicy Policy);
+
/**
* \brief Retrieve the display name for the entity referenced by this cursor.
*
diff --git a/test/Index/print-display-names.cpp b/test/Index/print-display-names.cpp
index 94fe4665e6..5ba10e43bc 100644
--- a/tools/clang/test/Index/print-display-names.cpp
+++ b/tools/clang/test/Index/print-display-names.cpp
@@ -12,9 +12,20 @@ void g(ClassTmpl<T, T>);
template<> void g<int>(ClassTmpl<int, int>);
-// RUN: c-index-test -test-load-source all-display %s | FileCheck %s
-// CHECK: print-display-names.cpp:2:7: ClassTemplate=ClassTmpl<T, typename>:2:7
-// CHECK: print-display-names.cpp:6:16: ClassDecl=ClassTmpl<Integer, Integer>:6:16 (Definition)
-// CHECK: print-display-names.cpp:8:6: FunctionDecl=f(ClassTmpl<float, Integer>):8:6
-// CHECK: print-display-names.cpp:11:6: FunctionTemplate=g(ClassTmpl<T, T>):11:6
-// CHECK: print-display-names.cpp:13:17: FunctionDecl=g<>(ClassTmpl<int, int>):13:17 [Specialization of g:11:6]
+// RUN: c-index-test -test-load-source all-display %s | FileCheck %s --check-prefix=DISPLAY_NAME
+// DISPLAY_NAME: print-display-names.cpp:2:7: ClassTemplate=ClassTmpl<T, typename>:2:7
+// DISPLAY_NAME: print-display-names.cpp:6:16: ClassDecl=ClassTmpl<Integer, Integer>:6:16 (Definition)
+// DISPLAY_NAME: print-display-names.cpp:8:6: FunctionDecl=f(ClassTmpl<float, Integer>):8:6
+// DISPLAY_NAME: print-display-names.cpp:11:6: FunctionTemplate=g(ClassTmpl<T, T>):11:6
+// DISPLAY_NAME: print-display-names.cpp:13:17: FunctionDecl=g<>(ClassTmpl<int, int>):13:17 [Specialization of g:11:6]
+
+// RUN: env CINDEXTEST_PRINTINGPOLICY_TERSEOUTPUT=1 c-index-test -test-load-source all-pretty %s | FileCheck %s --check-prefix=PRETTY
+// PRETTY: print-display-names.cpp:2:7: ClassTemplate=template <typename T, typename > class ClassTmpl {}:2:7 (Definition) Extent=[1:1 - 2:20]
+// PRETTY: print-display-names.cpp:4:13: TypedefDecl=typedef int Integer:4:13 (Definition) Extent=[4:1 - 4:20]
+// PRETTY: print-display-names.cpp:6:16: ClassDecl=template<> class ClassTmpl<int, int> {}:6:16 (Definition) [Specialization of ClassTmpl:2:7] Extent=[6:1 - 6:43]
+// PRETTY: print-display-names.cpp:8:6: FunctionDecl=void f(ClassTmpl<float, Integer> p):8:6 Extent=[8:1 - 8:36]
+// PRETTY: print-display-names.cpp:8:34: ParmDecl=ClassTmpl<float, Integer> p:8:34 (Definition) Extent=[8:8 - 8:35]
+// PRETTY: print-display-names.cpp:11:6: FunctionTemplate=template <typename T> void g(ClassTmpl<T, T>):11:6 Extent=[10:1 - 11:24]
+// PRETTY: print-display-names.cpp:11:23: ParmDecl=ClassTmpl<T, T>:11:23 (Definition) Extent=[11:8 - 11:23]
+// PRETTY: print-display-names.cpp:13:17: FunctionDecl=template<> void g<int>(ClassTmpl<int, int>):13:17 [Specialization of g:11:6] [Template arg 0: kind: 1, type: int] Extent=[13:1 - 13:44]
+// PRETTY: print-display-names.cpp:13:43: ParmDecl=ClassTmpl<int, int>:13:43 (Definition) Extent=[13:24 - 13:43]
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 759ed449a4..ce2f549234 100644
--- a/tools/clang/tools/c-index-test/c-index-test.c
+++ b/tools/clang/tools/c-index-test/c-index-test.c
@@ -86,6 +86,69 @@ static unsigned getDefaultParsingOptions() {
return options;
}
+static void ModifyPrintingPolicyAccordingToEnv(CXPrintingPolicy Policy) {
+ struct Mapping {
+ const char *name;
+ enum CXPrintingPolicyProperty property;
+ };
+ struct Mapping mappings[] = {
+ {"CINDEXTEST_PRINTINGPOLICY_INDENTATION", CXPrintingPolicy_Indentation},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSPECIFIERS",
+ CXPrintingPolicy_SuppressSpecifiers},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSTAGKEYWORD",
+ CXPrintingPolicy_SuppressTagKeyword},
+ {"CINDEXTEST_PRINTINGPOLICY_INCLUDETAGDEFINITION",
+ CXPrintingPolicy_IncludeTagDefinition},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSCOPE",
+ CXPrintingPolicy_SuppressScope},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSUNWRITTENSCOPE",
+ CXPrintingPolicy_SuppressUnwrittenScope},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSINITIALIZERS",
+ CXPrintingPolicy_SuppressInitializers},
+ {"CINDEXTEST_PRINTINGPOLICY_CONSTANTARRAYSIZEASWRITTEN",
+ CXPrintingPolicy_ConstantArraySizeAsWritten},
+ {"CINDEXTEST_PRINTINGPOLICY_ANONYMOUSTAGLOCATIONS",
+ CXPrintingPolicy_AnonymousTagLocations},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSTRONGLIFETIME",
+ CXPrintingPolicy_SuppressStrongLifetime},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSLIFETIMEQUALIFIERS",
+ CXPrintingPolicy_SuppressLifetimeQualifiers},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSTEMPLATEARGSINCXXCONSTRUCTORS",
+ CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors},
+ {"CINDEXTEST_PRINTINGPOLICY_BOOL", CXPrintingPolicy_Bool},
+ {"CINDEXTEST_PRINTINGPOLICY_RESTRICT", CXPrintingPolicy_Restrict},
+ {"CINDEXTEST_PRINTINGPOLICY_ALIGNOF", CXPrintingPolicy_Alignof},
+ {"CINDEXTEST_PRINTINGPOLICY_UNDERSCOREALIGNOF",
+ CXPrintingPolicy_UnderscoreAlignof},
+ {"CINDEXTEST_PRINTINGPOLICY_USEVOIDFORZEROPARAMS",
+ CXPrintingPolicy_UseVoidForZeroParams},
+ {"CINDEXTEST_PRINTINGPOLICY_TERSEOUTPUT", CXPrintingPolicy_TerseOutput},
+ {"CINDEXTEST_PRINTINGPOLICY_POLISHFORDECLARATION",
+ CXPrintingPolicy_PolishForDeclaration},
+ {"CINDEXTEST_PRINTINGPOLICY_HALF", CXPrintingPolicy_Half},
+ {"CINDEXTEST_PRINTINGPOLICY_MSWCHAR", CXPrintingPolicy_MSWChar},
+ {"CINDEXTEST_PRINTINGPOLICY_INCLUDENEWLINES",
+ CXPrintingPolicy_IncludeNewlines},
+ {"CINDEXTEST_PRINTINGPOLICY_MSVCFORMATTING",
+ CXPrintingPolicy_MSVCFormatting},
+ {"CINDEXTEST_PRINTINGPOLICY_CONSTANTSASWRITTEN",
+ CXPrintingPolicy_ConstantsAsWritten},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSIMPLICITBASE",
+ CXPrintingPolicy_SuppressImplicitBase},
+ {"CINDEXTEST_PRINTINGPOLICY_FULLYQUALIFIEDNAME",
+ CXPrintingPolicy_FullyQualifiedName},
+ };
+
+ unsigned i;
+ for (i = 0; i < sizeof(mappings) / sizeof(struct Mapping); i++) {
+ char *value = getenv(mappings[i].name);
+ if (value) {
+ clang_PrintingPolicy_setProperty(Policy, mappings[i].property,
+ (unsigned)strtoul(value, 0L, 10));
+ }
+ }
+}
+
/** \brief Returns 0 in case of success, non-zero in case of a failure. */
static int checkForErrors(CXTranslationUnit TU);
@@ -356,7 +419,11 @@ static void PrintRange(CXSourceRange R, const char *str) {
PrintExtent(stdout, begin_line, begin_column, end_line, end_column);
}
-int want_display_name = 0;
+static enum DisplayType {
+ DisplayType_Spelling,
+ DisplayType_DisplayName,
+ DisplayType_Pretty
+} wanted_display_type = DisplayType_Spelling;
static void printVersion(const char *Prefix, CXVersion Version) {
if (Version.Major < 0)
@@ -656,6 +723,24 @@ static int lineCol_cmp(const void *p1, const void *p2) {
return (int)lhs->col - (int)rhs->col;
}
+static CXString CursorToText(CXCursor Cursor) {
+ switch (wanted_display_type) {
+ case DisplayType_Spelling:
+ return clang_getCursorSpelling(Cursor);
+ case DisplayType_DisplayName:
+ return clang_getCursorDisplayName(Cursor);
+ case DisplayType_Pretty:
+ default: {
+ CXString text;
+ CXPrintingPolicy Policy = clang_getCursorPrintingPolicy(Cursor);
+ ModifyPrintingPolicyAccordingToEnv(Policy);
+ text = clang_getCursorPrettyPrinted(Cursor, Policy);
+ clang_PrintingPolicy_dispose(Policy);
+ return text;
+ }
+ }
+}
+
static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
if (clang_isInvalid(Cursor.kind)) {
@@ -682,8 +767,7 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
int I;
ks = clang_getCursorKindSpelling(Cursor.kind);
- string = want_display_name? clang_getCursorDisplayName(Cursor)
- : clang_getCursorSpelling(Cursor);
+ string = CursorToText(Cursor);
printf("%s=%s", clang_getCString(ks),
clang_getCString(string));
clang_disposeString(ks);
@@ -1675,7 +1759,12 @@ static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
else if (!strcmp(filter, "all-display") ||
!strcmp(filter, "local-display")) {
ck = NULL;
- want_display_name = 1;
+ wanted_display_type = DisplayType_DisplayName;
+ }
+ else if (!strcmp(filter, "all-pretty") ||
+ !strcmp(filter, "local-pretty")) {
+ ck = NULL;
+ wanted_display_type = DisplayType_Pretty;
}
else if (!strcmp(filter, "none")) K = (enum CXCursorKind) ~0;
else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
@@ -1742,8 +1831,11 @@ int perform_test_load_source(int argc, const char **argv,
unsigned I;
Idx = clang_createIndex(/* excludeDeclsFromPCH */
- (!strcmp(filter, "local") ||
- !strcmp(filter, "local-display"))? 1 : 0,
+ (!strcmp(filter, "local") ||
+ !strcmp(filter, "local-display") ||
+ !strcmp(filter, "local-pretty"))
+ ? 1
+ : 0,
/* displayDiagnostics=*/1);
if ((CommentSchemaFile = parse_comments_schema(argc, argv))) {
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 45ee9803f2..72b14fdb53 100644
--- a/tools/clang/tools/libclang/CIndex.cpp
+++ b/tools/clang/tools/libclang/CIndex.cpp
@@ -4652,6 +4652,197 @@ CXStringSet *clang_Cursor_getCXXManglings(CXCursor C) {
return cxstring::createSet(Manglings);
}
+CXPrintingPolicy clang_getCursorPrintingPolicy(CXCursor C) {
+ if (clang_Cursor_isNull(C))
+ return 0;
+ return new PrintingPolicy(getCursorContext(C).getPrintingPolicy());
+}
+
+void clang_PrintingPolicy_dispose(CXPrintingPolicy Policy) {
+ if (Policy)
+ delete static_cast<PrintingPolicy *>(Policy);
+}
+
+unsigned
+clang_PrintingPolicy_getProperty(CXPrintingPolicy Policy,
+ enum CXPrintingPolicyProperty Property) {
+ if (!Policy)
+ return 0;
+
+ PrintingPolicy *P = static_cast<PrintingPolicy *>(Policy);
+ switch (Property) {
+ case CXPrintingPolicy_Indentation:
+ return P->Indentation;
+ case CXPrintingPolicy_SuppressSpecifiers:
+ return P->SuppressSpecifiers;
+ case CXPrintingPolicy_SuppressTagKeyword:
+ return P->SuppressTagKeyword;
+ case CXPrintingPolicy_IncludeTagDefinition:
+ return P->IncludeTagDefinition;
+ case CXPrintingPolicy_SuppressScope:
+ return P->SuppressScope;
+ case CXPrintingPolicy_SuppressUnwrittenScope:
+ return P->SuppressUnwrittenScope;
+ case CXPrintingPolicy_SuppressInitializers:
+ return P->SuppressInitializers;
+ case CXPrintingPolicy_ConstantArraySizeAsWritten:
+ return P->ConstantArraySizeAsWritten;
+ case CXPrintingPolicy_AnonymousTagLocations:
+ return P->AnonymousTagLocations;
+ case CXPrintingPolicy_SuppressStrongLifetime:
+ return P->SuppressStrongLifetime;
+ case CXPrintingPolicy_SuppressLifetimeQualifiers:
+ return P->SuppressLifetimeQualifiers;
+ case CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors:
+ return P->SuppressTemplateArgsInCXXConstructors;
+ case CXPrintingPolicy_Bool:
+ return P->Bool;
+ case CXPrintingPolicy_Restrict:
+ return P->Restrict;
+ case CXPrintingPolicy_Alignof:
+ return P->Alignof;
+ case CXPrintingPolicy_UnderscoreAlignof:
+ return P->UnderscoreAlignof;
+ case CXPrintingPolicy_UseVoidForZeroParams:
+ return P->UseVoidForZeroParams;
+ case CXPrintingPolicy_TerseOutput:
+ return P->TerseOutput;
+ case CXPrintingPolicy_PolishForDeclaration:
+ return P->PolishForDeclaration;
+ case CXPrintingPolicy_Half:
+ return P->Half;
+ case CXPrintingPolicy_MSWChar:
+ return P->MSWChar;
+ case CXPrintingPolicy_IncludeNewlines:
+ return P->IncludeNewlines;
+ case CXPrintingPolicy_MSVCFormatting:
+ return P->MSVCFormatting;
+ case CXPrintingPolicy_ConstantsAsWritten:
+ // Ops, not yet there in clang 5.0 and we do not need it.
+ return 0;
+ case CXPrintingPolicy_SuppressImplicitBase:
+ // Ops, not yet there in clang 5.0 and we do not need it.
+ return 0;
+ case CXPrintingPolicy_FullyQualifiedName:
+ return P->FullyQualifiedName;
+ }
+
+ assert(false && "Invalid CXPrintingPolicyProperty");
+ return 0;
+}
+
+void clang_PrintingPolicy_setProperty(CXPrintingPolicy Policy,
+ enum CXPrintingPolicyProperty Property,
+ unsigned Value) {
+ if (!Policy)
+ return;
+
+ PrintingPolicy *P = static_cast<PrintingPolicy *>(Policy);
+ switch (Property) {
+ case CXPrintingPolicy_Indentation:
+ P->Indentation = Value;
+ return;
+ case CXPrintingPolicy_SuppressSpecifiers:
+ P->SuppressSpecifiers = Value;
+ return;
+ case CXPrintingPolicy_SuppressTagKeyword:
+ P->SuppressTagKeyword = Value;
+ return;
+ case CXPrintingPolicy_IncludeTagDefinition:
+ P->IncludeTagDefinition = Value;
+ return;
+ case CXPrintingPolicy_SuppressScope:
+ P->SuppressScope = Value;
+ return;
+ case CXPrintingPolicy_SuppressUnwrittenScope:
+ P->SuppressUnwrittenScope = Value;
+ return;
+ case CXPrintingPolicy_SuppressInitializers:
+ P->SuppressInitializers = Value;
+ return;
+ case CXPrintingPolicy_ConstantArraySizeAsWritten:
+ P->ConstantArraySizeAsWritten = Value;
+ return;
+ case CXPrintingPolicy_AnonymousTagLocations:
+ P->AnonymousTagLocations = Value;
+ return;
+ case CXPrintingPolicy_SuppressStrongLifetime:
+ P->SuppressStrongLifetime = Value;
+ return;
+ case CXPrintingPolicy_SuppressLifetimeQualifiers:
+ P->SuppressLifetimeQualifiers = Value;
+ return;
+ case CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors:
+ P->SuppressTemplateArgsInCXXConstructors = Value;
+ return;
+ case CXPrintingPolicy_Bool:
+ P->Bool = Value;
+ return;
+ case CXPrintingPolicy_Restrict:
+ P->Restrict = Value;
+ return;
+ case CXPrintingPolicy_Alignof:
+ P->Alignof = Value;
+ return;
+ case CXPrintingPolicy_UnderscoreAlignof:
+ P->UnderscoreAlignof = Value;
+ return;
+ case CXPrintingPolicy_UseVoidForZeroParams:
+ P->UseVoidForZeroParams = Value;
+ return;
+ case CXPrintingPolicy_TerseOutput:
+ P->TerseOutput = Value;
+ return;
+ case CXPrintingPolicy_PolishForDeclaration:
+ P->PolishForDeclaration = Value;
+ return;
+ case CXPrintingPolicy_Half:
+ P->Half = Value;
+ return;
+ case CXPrintingPolicy_MSWChar:
+ P->MSWChar = Value;
+ return;
+ case CXPrintingPolicy_IncludeNewlines:
+ P->IncludeNewlines = Value;
+ return;
+ case CXPrintingPolicy_MSVCFormatting:
+ P->MSVCFormatting = Value;
+ return;
+ case CXPrintingPolicy_ConstantsAsWritten:
+ // Ops, not yet there in clang 5.0 and we do not need it.
+ return;
+ case CXPrintingPolicy_SuppressImplicitBase:
+ // Ops, not yet there in clang 5.0 and we do not need it.
+ return;
+ case CXPrintingPolicy_FullyQualifiedName:
+ P->FullyQualifiedName = Value;
+ return;
+ }
+
+ assert(false && "Invalid CXPrintingPolicyProperty");
+}
+
+CXString clang_getCursorPrettyPrinted(CXCursor C, CXPrintingPolicy cxPolicy) {
+ if (clang_Cursor_isNull(C))
+ return cxstring::createEmpty();
+
+ if (clang_isDeclaration(C.kind)) {
+ const Decl *D = getCursorDecl(C);
+ if (!D)
+ return cxstring::createEmpty();
+
+ SmallString<128> Str;
+ llvm::raw_svector_ostream OS(Str);
+ PrintingPolicy *UserPolicy = static_cast<PrintingPolicy *>(cxPolicy);
+ D->print(OS, UserPolicy ? *UserPolicy
+ : getCursorContext(C).getPrintingPolicy());
+
+ return cxstring::createDup(OS.str());
+ }
+
+ return cxstring::createEmpty();
+}
+
CXString clang_getCursorDisplayName(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return clang_getCursorSpelling(C);
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index c788abb881..ed4773b132 100644
--- a/tools/clang/tools/libclang/libclang.exports
+++ b/tools/clang/tools/libclang/libclang.exports
@@ -175,6 +175,8 @@ clang_getCursorAvailability
clang_getCursorCompletionString
clang_getCursorDefinition
clang_getCursorDisplayName
+clang_getCursorPrintingPolicy
+clang_getCursorPrettyPrinted
clang_getCursorExtent
clang_getCursorExceptionSpecificationType
clang_getCursorKind
@@ -355,3 +357,6 @@ clang_EvalResult_isUnsignedInt
clang_EvalResult_getAsDouble
clang_EvalResult_getAsStr
clang_EvalResult_dispose
+clang_PrintingPolicy_getProperty
+clang_PrintingPolicy_setProperty
+clang_PrintingPolicy_dispose
diff --git a/unittests/libclang/LibclangTest.cpp b/unittests/libclang/LibclangTest.cpp
index f2a96d6be6..a9f5ee1da4 100644
--- a/tools/clang/unittests/libclang/LibclangTest.cpp
+++ b/tools/clang/unittests/libclang/LibclangTest.cpp
@@ -572,3 +572,33 @@ TEST_F(LibclangReparseTest, clang_parseTranslationUnit2FullArgv) {
EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU));
DisplayDiagnostics();
}
+
+class LibclangPrintingPolicyTest : public LibclangParseTest {
+public:
+ CXPrintingPolicy Policy = nullptr;
+
+ void SetUp() override {
+ LibclangParseTest::SetUp();
+ std::string File = "file.cpp";
+ WriteFile(File, "int i;\n");
+ ClangTU = clang_parseTranslationUnit(Index, File.c_str(), nullptr, 0,
+ nullptr, 0, TUFlags);
+ CXCursor TUCursor = clang_getTranslationUnitCursor(ClangTU);
+ Policy = clang_getCursorPrintingPolicy(TUCursor);
+ }
+ void TearDown() override {
+ clang_PrintingPolicy_dispose(Policy);
+ LibclangParseTest::TearDown();
+ }
+};
+
+TEST_F(LibclangPrintingPolicyTest, SetAndGetProperties) {
+ for (unsigned Value = 0; Value < 2; ++Value) {
+ for (int I = 0; I < CXPrintingPolicy_LastProperty; ++I) {
+ auto Property = static_cast<enum CXPrintingPolicyProperty>(I);
+
+ clang_PrintingPolicy_setProperty(Policy, Property, Value);
+ EXPECT_EQ(Value, clang_PrintingPolicy_getProperty(Policy, Property));
+ }
+ }
+}

View File

@@ -9,41 +9,106 @@ The patches in this directory are applied to LLVM/Clang with:
Backported changes
------------------
##### D35355_Fix-templated-type-alias-completion-when-using-global-completion-cache.patch
##### 110_D41016_Fix-crash-in-unused-lambda-capture-warning-for-VLAs.patch
* <https://reviews.llvm.org/D41016>
[Sema] Fix crash in unused-lambda-capture warning for VLAs
##### 010_D35355_Fix-templated-type-alias-completion-when-using-global-completion-cache.patch
* <https://reviews.llvm.org/D35355>
Fixes completion involving templated type alias.
##### D37435_Dont-show-deleted-function-constructor-candidates-for-code-completion.patch
##### 120_D41688_Fix-crash-on-code-completion-in-comment-in-included-file.patch
* <https://reviews.llvm.org/D37435>
* <https://bugs.llvm.org/show_bug.cgi?id=34402>
* <https://reviews.llvm.org/D41688>
Fixes completion involving implicitly deleted copy constructors.
[Lex] Fix crash on code completion in comment in included file.
##### rL310905_Avoid-PointerIntPair-of-constexpr-EvalInfo-structs.patch
##### 100_D40841_Fix-a-crash-on-C++17-AST-for-non-trivial-construction-into-a-trivial-brace-initialize.patch
* <https://reviews.llvm.org/rL310905>
* <https://bugs.llvm.org/show_bug.cgi?id=32018>
* <https://reviews.llvm.org/D40841>
Fixes build/miscompilation of LLVM/Clang with MinGW, which enables generation
of profile-guided-optimization builds for Windows.
[analyzer] Fix a crash on C++17 AST for non-trivial construction into a trivial brace initializer.
##### 090_D40746_Correctly-handle-line-table-entries-without-filenames-during-AST-serialization.patch
* <https://reviews.llvm.org/D40746>
Correctly handle line table entries without filenames during AST serialization
Fixes crash during a reparse.
##### 050_D40027_Fix-cursors-for-in-class-initializer-of-field-declarations.patch
* <https://reviews.llvm.org/D40027>
* <https://bugs.llvm.org/show_bug.cgi?id=33745>
[libclang] Fix cursors for in-class initializer of field declarations
Fixes AST access to initializers of class members. Affects mostly semantic highlighting and highlighting of local uses.
##### 070_D40561_Fix-cursors-for-functions-with-trailing-return-type.patch
* <https://reviews.llvm.org/D40561>
[libclang] Fix cursors for functions with trailing return type
##### 060_D40072_Support-querying-whether-a-declaration-is-invalid.patch
* <https://reviews.llvm.org/D40072>
[libclang] Add support for checking abstractness of records
Would need https://codereview.qt-project.org/#/c/211497/ on Qt Creator side.
##### 040_D39957_Honor-TerseOutput-for-constructors.patch
* <https://reviews.llvm.org/D39957>
[DeclPrinter] Honor TerseOutput for constructors
Avoids printing member initialization list and body for constructor.
##### 080_D40643_Add-function-to-get-the-buffer-for-a-file.patch
* <https://reviews.llvm.org/D40643>
* <https://reviews.llvm.org/rL319881>
[libclang] Add function to get the buffer for a file
Together with https://codereview.qt-project.org/#/c/212972/ fixes highlighting
##### 030_D38615_Only-mark-CXCursors-for-explicit-attributes-with-a-type.patch
* <https://reviews.llvm.org/D38615>
[libclang] Only mark CXCursors for explicit attributes with a type
Some classes have totally broken highlighting (like classes inside texteditor.cpp)
##### 170_D40013_DeclPrinter-Allow-printing-fully-qualified-name.patch
##### 180_D39903_libclang-Allow-pretty-printing-declarations.patch
* <https://reviews.llvm.org/D40013>
* <https://reviews.llvm.org/D39903>
[DeclPrinter] Allow printing fully qualified name of function declaration
[libclang] Allow pretty printing declarations
Improves pretty printing for tooltips.
Additional changes
------------------
##### QTCREATORBUG-15449_Fix-files-lock-on-Windows.patch
##### 160_QTCREATORBUG-15449_Fix-files-lock-on-Windows.patch
* <https://reviews.llvm.org/D35200>
* <https://bugreports.qt.io/browse/QTCREATORBUG-15449>
Significantly reduces problems when saving a header file on Windows.
##### QTCREATORBUG-15157_Link-with-clazy.patch
##### 150_QTCREATORBUG-15157_Link-with-clazy_llvm.patch
##### 130_QTCREATORBUG-15157_Link-with-clazy_clang.patch
##### 140_QTCREATORBUG-15157_Link-with-clazy_extra.patch
* <https://bugreports.qt.io/browse/QTCREATORBUG-15157>
Introduces the flag CLANG_ENABLE_CLAZY to link libclang with Clazy and forces
link for Clazy checks and plugin registry entry.
Builds Clazy as an LLVM part and forces link for Clazy plugin registry entry.

View File

@@ -1,88 +0,0 @@
diff --git a/tools/clang/lib/AST/ExprConstant.cpp b/tools/clang/lib/AST/ExprConstant.cpp
index a26b608082..effd72c764 100644
--- a/tools/clang/lib/AST/ExprConstant.cpp
+++ b/tools/clang/lib/AST/ExprConstant.cpp
@@ -537,7 +537,11 @@ namespace {
/// rules. For example, the RHS of (0 && foo()) is not evaluated. We can
/// evaluate the expression regardless of what the RHS is, but C only allows
/// certain things in certain situations.
+#ifndef _WIN32
struct LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) EvalInfo {
+#else
+ struct EvalInfo {
+#endif
ASTContext &Ctx;
/// EvalStatus - Contains information about the evaluation.
@@ -575,7 +579,21 @@ namespace {
/// The current array initialization index, if we're performing array
/// initialization.
+#ifndef _WIN32
uint64_t ArrayInitIndex = -1;
+#else
+ /// uint64_t value is split into two uint32_t values as a workaround
+ /// to deal with mingw 32-bit miscompilation
+ uint32_t ArrayInitIndex[2] = {static_cast<uint32_t>(-1), static_cast<uint32_t>(-1)};
+ uint64_t GetArrayInitIndex() {
+ return (static_cast<uint64_t>(ArrayInitIndex[0]) << 32)
+ + static_cast<uint64_t>(ArrayInitIndex[1]);
+ }
+ void SetArrayInitIndex(uint64_t index) {
+ ArrayInitIndex[0] = static_cast<uint32_t>(index >> 32);
+ ArrayInitIndex[1] = static_cast<uint32_t>(index);
+ }
+#endif
/// HasActiveDiagnostic - Was the previous diagnostic stored? If so, further
/// notes attached to it will also be stored, otherwise they will not be.
@@ -922,6 +940,7 @@ namespace {
uint64_t OuterIndex;
public:
+#ifndef _WIN32
ArrayInitLoopIndex(EvalInfo &Info)
: Info(Info), OuterIndex(Info.ArrayInitIndex) {
Info.ArrayInitIndex = 0;
@@ -929,6 +948,19 @@ namespace {
~ArrayInitLoopIndex() { Info.ArrayInitIndex = OuterIndex; }
operator uint64_t&() { return Info.ArrayInitIndex; }
+#else
+ ArrayInitLoopIndex(EvalInfo &Info)
+ : Info(Info), OuterIndex(Info.GetArrayInitIndex()) {
+ Info.SetArrayInitIndex(0);
+ }
+ ~ArrayInitLoopIndex() { Info.SetArrayInitIndex(OuterIndex); }
+
+ operator uint64_t() { return Info.GetArrayInitIndex(); }
+ ArrayInitLoopIndex& operator++() {
+ Info.SetArrayInitIndex(Info.GetArrayInitIndex() + 1);
+ return *this;
+ }
+#endif
};
};
@@ -6973,13 +7005,21 @@ public:
}
bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E) {
+#ifndef _WIN32
if (Info.ArrayInitIndex == uint64_t(-1)) {
+#else
+ if (Info.GetArrayInitIndex() == uint64_t(-1)) {
+#endif
// We were asked to evaluate this subexpression independent of the
// enclosing ArrayInitLoopExpr. We can't do that.
Info.FFDiag(E);
return false;
}
+#ifndef _WIN32
return Success(Info.ArrayInitIndex, E);
+#else
+ return Success(Info.GetArrayInitIndex(), E);
+#endif
}
// Note, GNU defines __null as an integer, not a pointer.

View File

@@ -1,10 +1,11 @@
import qbs 1.0
import qbs.FileInfo
import QtcFunctions
QtcProduct {
type: ["dynamiclibrary", "dynamiclibrary_symlink", "qtc.dev-module"]
installDir: qtc.ide_library_path
installTags: ["dynamiclibrary", "dynamiclibrary_symlink"]
installTags: ["dynamiclibrary", "dynamiclibrary_symlink", "debuginfo_dll"]
useNonGuiPchFile: true
Depends {
condition: qtc.testsEnabled
@@ -12,7 +13,7 @@ QtcProduct {
}
targetName: QtcFunctions.qtLibraryName(qbs, name)
destinationDirectory: qtc.ide_library_path
destinationDirectory: FileInfo.joinPaths(buildDirectory, qtc.ide_library_path)
cpp.linkerFlags: {
var flags = base;

View File

@@ -5,7 +5,7 @@ import QtcFunctions
QtcProduct {
type: ["dynamiclibrary", "pluginSpec", "qtc.dev-module"]
installDir: qtc.ide_plugin_path
installTags: ["dynamiclibrary"]
installTags: ["dynamiclibrary", "debuginfo_dll"]
useGuiPchFile: true
property var pluginJsonReplacements
@@ -13,7 +13,7 @@ QtcProduct {
property var pluginTestDepends: []
targetName: QtcFunctions.qtLibraryName(qbs, name)
destinationDirectory: qtc.ide_plugin_path
destinationDirectory: FileInfo.joinPaths(buildDirectory, qtc.ide_plugin_path)
Depends { name: "ExtensionSystem" }
Depends { name: "pluginjson" }

View File

@@ -8,7 +8,7 @@ Product {
version: qtc.qtcreator_version
property bool install: true
property string installDir
property string installSourceBase
property string installSourceBase: destinationDirectory
property stringList installTags: type
property string fileName: FileInfo.fileName(sourceDirectory) + ".qbs"
property bool useNonGuiPchFile: false

View File

@@ -5,6 +5,7 @@ QtcProduct {
type: ["application"]
consoleApplication: true
installDir: qtc.ide_libexec_path
installTags: base.concat(["debuginfo_app"])
useNonGuiPchFile: true
cpp.rpaths: {

View File

@@ -22,8 +22,7 @@ QtcProduct {
property bool isBundle: qbs.targetOS.contains("darwin") && bundle.isBundle
installDir: isBundle ? qtc.ide_app_path : qtc.ide_bin_path
installTags: isBundle ? ["bundle.content"] : base
installSourceBase: isBundle ? buildDirectory : base
installTags: (isBundle ? ["bundle.content"] : base).concat(["debuginfo_app"])
property bool qtcRunnable: true
bundle.identifier: qtc.ide_bundle_identifier

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -15,12 +15,10 @@
** as extensions by SQLite should #include this file instead of
** sqlite3.h.
*/
#ifndef _SQLITE3EXT_H_
#define _SQLITE3EXT_H_
#ifndef SQLITE3EXT_H
#define SQLITE3EXT_H
#include "sqlite3.h"
typedef struct sqlite3_api_routines sqlite3_api_routines;
/*
** The following structure holds pointers to all of the SQLite API
** routines.
@@ -136,7 +134,7 @@ struct sqlite3_api_routines {
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
const char*,const char*),void*);
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
char * (*snprintf)(int,char*,const char*,...);
char * (*xsnprintf)(int,char*,const char*,...);
int (*step)(sqlite3_stmt*);
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
char const**,char const**,int*,int*,int*);
@@ -248,7 +246,7 @@ struct sqlite3_api_routines {
int (*uri_boolean)(const char*,const char*,int);
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
const char *(*uri_parameter)(const char*,const char*);
char *(*vsnprintf)(int,char*,const char*,va_list);
char *(*xvsnprintf)(int,char*,const char*,va_list);
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
/* Version 3.8.7 and later */
int (*auto_extension)(void(*)(void));
@@ -267,8 +265,45 @@ struct sqlite3_api_routines {
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
void(*)(void*), unsigned char);
int (*strglob)(const char*,const char*);
/* Version 3.8.11 and later */
sqlite3_value *(*value_dup)(const sqlite3_value*);
void (*value_free)(sqlite3_value*);
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
/* Version 3.9.0 and later */
unsigned int (*value_subtype)(sqlite3_value*);
void (*result_subtype)(sqlite3_context*,unsigned int);
/* Version 3.10.0 and later */
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
int (*strlike)(const char*,const char*,unsigned int);
int (*db_cacheflush)(sqlite3*);
/* Version 3.12.0 and later */
int (*system_errno)(sqlite3*);
/* Version 3.14.0 and later */
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
char *(*expanded_sql)(sqlite3_stmt*);
/* Version 3.18.0 and later */
void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
/* Version 3.20.0 and later */
int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
sqlite3_stmt**,const char**);
int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
sqlite3_stmt**,const void**);
int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
void *(*value_pointer)(sqlite3_value*,const char*);
};
/*
** This is the function signature used for all extension entry points. It
** is also defined in the file "loadext.c".
*/
typedef int (*sqlite3_loadext_entry)(
sqlite3 *db, /* Handle to the database. */
char **pzErrMsg, /* Used to set error string on failure. */
const sqlite3_api_routines *pThunk /* Extension API function pointers. */
);
/*
** The following macros redefine the API routines so that they are
** redirected through the global sqlite3_api structure.
@@ -280,7 +315,7 @@ struct sqlite3_api_routines {
** the API. So the redefinition macros are only valid if the
** SQLITE_CORE macros is undefined.
*/
#ifndef SQLITE_CORE
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
@@ -383,7 +418,7 @@ struct sqlite3_api_routines {
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
#define sqlite3_snprintf sqlite3_api->snprintf
#define sqlite3_snprintf sqlite3_api->xsnprintf
#define sqlite3_step sqlite3_api->step
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
@@ -407,6 +442,7 @@ struct sqlite3_api_routines {
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
#define sqlite3_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
@@ -482,7 +518,7 @@ struct sqlite3_api_routines {
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
#define sqlite3_uri_int64 sqlite3_api->uri_int64
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
/* Version 3.8.7 and later */
#define sqlite3_auto_extension sqlite3_api->auto_extension
@@ -497,9 +533,34 @@ struct sqlite3_api_routines {
#define sqlite3_result_blob64 sqlite3_api->result_blob64
#define sqlite3_result_text64 sqlite3_api->result_text64
#define sqlite3_strglob sqlite3_api->strglob
#endif /* SQLITE_CORE */
/* Version 3.8.11 and later */
#define sqlite3_value_dup sqlite3_api->value_dup
#define sqlite3_value_free sqlite3_api->value_free
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
/* Version 3.9.0 and later */
#define sqlite3_value_subtype sqlite3_api->value_subtype
#define sqlite3_result_subtype sqlite3_api->result_subtype
/* Version 3.10.0 and later */
#define sqlite3_status64 sqlite3_api->status64
#define sqlite3_strlike sqlite3_api->strlike
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
/* Version 3.12.0 and later */
#define sqlite3_system_errno sqlite3_api->system_errno
/* Version 3.14.0 and later */
#define sqlite3_trace_v2 sqlite3_api->trace_v2
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
/* Version 3.18.0 and later */
#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
/* Version 3.20.0 and later */
#define sqlite3_prepare_v3 sqlite3_api->prepare_v3
#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3
#define sqlite3_bind_pointer sqlite3_api->bind_pointer
#define sqlite3_result_pointer sqlite3_api->result_pointer
#define sqlite3_value_pointer sqlite3_api->value_pointer
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#ifndef SQLITE_CORE
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
/* This case when the file really is being compiled as a loadable
** extension */
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
@@ -514,4 +575,4 @@ struct sqlite3_api_routines {
# define SQLITE_EXTENSION_INIT3 /*no-op*/
#endif
#endif /* _SQLITE3EXT_H_ */
#endif /* SQLITE3EXT_H */

View File

@@ -458,7 +458,7 @@ unittest_public:
private:
IdCache m_idCache;
WatcherEntries m_watchedEntries;
ChangedFilePathCompressor<Timer> m_changedFilePathCompressor{};
ChangedFilePathCompressor<Timer> m_changedFilePathCompressor;
FileSystemWatcher m_fileSystemWatcher;
FilePathCachingInterface &m_pathCache;
ClangPathWatcherNotifier *m_notifier;

View File

@@ -31,10 +31,6 @@
#include <utils/smallstringfwd.h>
#ifdef UNIT_TESTS
#include <gtest/gtest.h>
#endif
#if defined(CLANGSUPPORT_BUILD_LIB)
# define CLANGSUPPORT_EXPORT Q_DECL_EXPORT
#elif defined(CLANGSUPPORT_BUILD_STATIC_LIB)

View File

@@ -45,6 +45,7 @@ public:
createLocationsTable();
createSourcesTable();
createDirectoriesTable();
createProjectPartsTable();
transaction.commit();
}
@@ -102,6 +103,19 @@ public:
table.initialize(database);
}
void createProjectPartsTable()
{
Sqlite::Table table;
table.setUseIfNotExists(true);
table.setName("projectParts");
table.addColumn("projectPartId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey);
const Sqlite::Column &projectPartNameColumn = table.addColumn("projectPartName", Sqlite::ColumnType::Text);
table.addColumn("compilerArguments", Sqlite::ColumnType::Text);
table.addIndex({projectPartNameColumn});
table.initialize(database);
}
public:
DatabaseType &database;
};

View File

@@ -46,6 +46,7 @@ HEADERS += \
$$PWD/sqliteindex.h \
$$PWD/sqlitebasestatement.h
DEFINES += SQLITE_THREADSAFE=2 SQLITE_ENABLE_FTS4 SQLITE_ENABLE_FTS3_PARENTHESIS SQLITE_ENABLE_UNLOCK_NOTIFY SQLITE_ENABLE_COLUMN_METADATA
DEFINES += SQLITE_THREADSAFE=2 SQLITE_ENABLE_FTS4 SQLITE_ENABLE_FTS3_PARENTHESIS \
SQLITE_ENABLE_UNLOCK_NOTIFY SQLITE_ENABLE_COLUMN_METADATA SQLITE_ENABLE_JSON1
contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols

View File

@@ -10,7 +10,8 @@ QtcLibrary {
"SQLITE_ENABLE_FTS4",
"SQLITE_ENABLE_FTS3_PARENTHESIS",
"SQLITE_ENABLE_UNLOCK_NOTIFY",
"SQLITE_ENABLE_COLUMN_METADATA"
"SQLITE_ENABLE_COLUMN_METADATA",
"SQLITE_ENABLE_JSON1"
])
cpp.optimization: "fast"
cpp.dynamicLibraries: base.concat((qbs.targetOS.contains("unix") && !qbs.targetOS.contains("bsd"))

View File

@@ -82,6 +82,11 @@ public:
return m_databaseBackend.lastInsertedRowId();
}
void setLastInsertedRowId(int64_t rowId)
{
m_databaseBackend.setLastInsertedRowId(rowId);
}
int changesCount()
{
return m_databaseBackend.changesCount();

View File

@@ -172,6 +172,11 @@ int64_t DatabaseBackend::lastInsertedRowId() const
return sqlite3_last_insert_rowid(sqliteDatabaseHandle());
}
void DatabaseBackend::setLastInsertedRowId(int64_t rowId)
{
sqlite3_set_last_insert_rowid(sqliteDatabaseHandle(), rowId);
}
void DatabaseBackend::execute(Utils::SmallStringView sqlStatement)
{
ReadWriteStatement statement(sqlStatement, m_database);

View File

@@ -72,6 +72,7 @@ public:
int totalChangesCount() const;
int64_t lastInsertedRowId() const;
void setLastInsertedRowId(int64_t rowId);
void execute(Utils::SmallStringView sqlStatement);

View File

@@ -39,11 +39,6 @@ QDebug operator<<(QDebug debug, const Utf8String &text)
return debug;
}
void PrintTo(const Utf8String &text, ::std::ostream* os)
{
*os << "\"" << text.toByteArray().data() << "\"";
}
std::ostream& operator<<(std::ostream &os, const Utf8String &utf8String)
{
using std::ostream;

View File

@@ -267,7 +267,6 @@ private:
};
SQLITE_EXPORT QDebug operator<<(QDebug debug, const Utf8String &text);
SQLITE_EXPORT void PrintTo(const Utf8String &text, ::std::ostream* os);
SQLITE_EXPORT std::ostream& operator<<(std::ostream &os, const Utf8String &utf8String);
#define Utf8StringLiteral(str) Utf8String::fromByteArray(QByteArrayLiteral(str))

View File

@@ -381,7 +381,7 @@ TimelineRenderPass::State *TimelineItemsRenderPass::update(const TimelineAbstrac
const TimelineRenderState *parentState,
State *oldState, int indexFrom,
int indexTo, bool stateChanged,
qreal spacing) const
float spacing) const
{
Q_UNUSED(stateChanged);
const TimelineModel *model = renderer->model();
@@ -416,8 +416,8 @@ TimelineRenderPass::State *TimelineItemsRenderPass::update(const TimelineAbstrac
state->expandedRow(row));
rowNode->material.setScale(
QVector2D(spacing / parentState->scale(),
static_cast<qreal>(model->expandedRowHeight(row))) /
static_cast<qreal>(TimelineModel::defaultRowHeight()));
static_cast<float>(model->expandedRowHeight(row))) /
static_cast<float>(TimelineModel::defaultRowHeight()));
rowNode->material.setSelectedItem(selectedItem);
rowNode->material.setSelectionColor(selectionColor);
}

View File

@@ -95,7 +95,7 @@ public:
static const TimelineItemsRenderPass *instance();
State *update(const TimelineAbstractRenderer *renderer, const TimelineRenderState *parentState,
State *state, int firstIndex, int lastIndex, bool stateChanged,
qreal spacing) const;
float spacing) const;
protected:
TimelineItemsRenderPass();
};

View File

@@ -415,13 +415,13 @@ float TimelineModel::relativeHeight(int index) const
return 1.0f;
}
int TimelineModel::rowMinValue(int rowNumber) const
qint64 TimelineModel::rowMinValue(int rowNumber) const
{
Q_UNUSED(rowNumber);
return 0;
}
int TimelineModel::rowMaxValue(int rowNumber) const
qint64 TimelineModel::rowMaxValue(int rowNumber) const
{
Q_UNUSED(rowNumber);
return 0;

View File

@@ -102,8 +102,8 @@ public:
Q_INVOKABLE virtual int typeId(int index) const;
Q_INVOKABLE virtual bool handlesTypeId(int typeId) const;
Q_INVOKABLE virtual float relativeHeight(int index) const;
Q_INVOKABLE virtual int rowMinValue(int rowNumber) const;
Q_INVOKABLE virtual int rowMaxValue(int rowNumber) const;
Q_INVOKABLE virtual qint64 rowMinValue(int rowNumber) const;
Q_INVOKABLE virtual qint64 rowMaxValue(int rowNumber) const;
Q_INVOKABLE int nextItemBySelectionId(int selectionId, qint64 time, int currentItem) const;
Q_INVOKABLE int nextItemByTypeId(int typeId, qint64 time, int currentItem) const;

View File

@@ -104,7 +104,7 @@ TimelineRenderPass::State *TimelineNotesRenderPass::update(const TimelineAbstrac
const TimelineRenderState *parentState,
State *oldState, int firstIndex,
int lastIndex, bool stateChanged,
qreal spacing) const
float spacing) const
{
Q_UNUSED(firstIndex);
Q_UNUSED(lastIndex);

View File

@@ -37,7 +37,7 @@ public:
State *update(const TimelineAbstractRenderer *renderer, const TimelineRenderState *parentState,
State *oldState, int firstIndex, int lastIndex, bool stateChanged,
qreal spacing) const;
float spacing) const;
private:
TimelineNotesRenderPass();

View File

@@ -63,8 +63,9 @@ QSGNode *TimelineOverviewRenderer::updatePaintNode(QSGNode *oldNode,
1.0, d->renderPasses.size());
}
qreal xSpacing = width() / d->zoomer->traceDuration();
qreal ySpacing = height() / (d->model->collapsedRowCount() * TimelineModel::defaultRowHeight());
float xSpacing = static_cast<float>(width() / d->zoomer->traceDuration());
float ySpacing = static_cast<float>(
height() / (d->model->collapsedRowCount() * TimelineModel::defaultRowHeight()));
for (int i = 0; i < d->renderPasses.length(); ++i) {
d->renderState->setPassState(i, d->renderPasses[i]->update(this, d->renderState,

View File

@@ -120,7 +120,7 @@ QSGNode *TimelineRenderer::updatePaintNode(QSGNode *node, UpdatePaintNodeData *u
return 0;
}
qreal spacing = width() / d->zoomer->windowDuration();
float spacing = static_cast<float>(width() / d->zoomer->windowDuration());
if (d->modelDirty) {
if (node)

View File

@@ -49,7 +49,7 @@ public:
virtual State *update(const TimelineAbstractRenderer *renderer,
const TimelineRenderState *parentState,
State *state, int indexFrom, int indexTo, bool stateChanged,
qreal spacing) const = 0;
float spacing) const = 0;
};
} // namespace Timeline

View File

@@ -28,7 +28,7 @@
namespace Timeline {
TimelineRenderState::TimelineRenderState(qint64 start, qint64 end, qreal scale, int numPasses) :
TimelineRenderState::TimelineRenderState(qint64 start, qint64 end, float scale, int numPasses) :
d_ptr(new TimelineRenderStatePrivate)
{
Q_D(TimelineRenderState);
@@ -70,7 +70,7 @@ qint64 TimelineRenderState::end() const
return d->end;
}
qreal TimelineRenderState::scale() const
float TimelineRenderState::scale() const
{
Q_D(const TimelineRenderState);
return d->scale;

View File

@@ -33,12 +33,12 @@ namespace Timeline {
class TIMELINE_EXPORT TimelineRenderState {
public:
TimelineRenderState(qint64 start, qint64 end, qreal scale, int numPasses);
TimelineRenderState(qint64 start, qint64 end, float scale, int numPasses);
~TimelineRenderState();
qint64 start() const;
qint64 end() const;
qreal scale() const;
float scale() const;
TimelineRenderPass::State *passState(int i);
const TimelineRenderPass::State *passState(int i) const;

View File

@@ -39,7 +39,7 @@ public:
qint64 start;
qint64 end;
qreal scale; // "native" scale, this stays the same through the life time of a state
float scale; // "native" scale, this stays the same through the life time of a state
QVector<TimelineRenderPass::State *> passes;
};

View File

@@ -64,7 +64,7 @@ private:
TimelineRenderPass::State *TimelineSelectionRenderPass::update(
const TimelineAbstractRenderer *renderer, const TimelineRenderState *parentState,
State *oldState, int firstIndex, int lastIndex, bool stateChanged, qreal spacing) const
State *oldState, int firstIndex, int lastIndex, bool stateChanged, float spacing) const
{
Q_UNUSED(stateChanged);

View File

@@ -38,7 +38,7 @@ public:
State *update(const TimelineAbstractRenderer *renderer, const TimelineRenderState *parentState,
State *state, int firstIndex, int lastIndex, bool stateChanged,
qreal spacing) const;
float spacing) const;
protected:
TimelineSelectionRenderPass();

View File

@@ -25,6 +25,7 @@
#include "settingsaccessor.h"
#include "asconst.h"
#include "qtcassert.h"
#include <QApplication>
@@ -150,99 +151,158 @@ void trackUserStickySettings(QVariantMap &userMap, const QVariantMap &sharedMap)
namespace Utils {
// --------------------------------------------------------------------
// BasicSettingsAccessor::Issue:
// --------------------------------------------------------------------
QMessageBox::StandardButtons BasicSettingsAccessor::Issue::allButtons() const
{
QMessageBox::StandardButtons result = QMessageBox::NoButton;
for (const QMessageBox::StandardButton &b : buttons.keys())
result |= b;
return result;
}
// --------------------------------------------------------------------
// BasicSettingsAccessor:
// --------------------------------------------------------------------
BasicSettingsAccessor::BasicSettingsAccessor(const FileName &baseFilePath, const QString &docType) :
m_baseFilePath(baseFilePath),
m_docType(docType)
/*!
* The BasicSettingsAccessor can be used to read/write settings in XML format.
*/
BasicSettingsAccessor::BasicSettingsAccessor(const QString &docType,
const QString &displayName,
const QString &applicationDisplayName) :
docType(docType),
displayName(displayName),
applicationDisplayName(applicationDisplayName)
{
QTC_CHECK(!m_baseFilePath.isEmpty());
QTC_CHECK(!m_docType.isEmpty());
}
BasicSettingsAccessor::~BasicSettingsAccessor() = default;
QVariantMap BasicSettingsAccessor::restoreSettings(QWidget *parent) const
{
Q_UNUSED(parent);
return readFile(m_baseFilePath);
}
bool BasicSettingsAccessor::saveSettings(const QVariantMap &data, QWidget *parent) const
{
return writeFile(m_baseFilePath, data, parent);
}
QVariantMap BasicSettingsAccessor::readFile(const FileName &path) const
{
PersistentSettingsReader reader;
if (!reader.load(path))
return QVariantMap();
return reader.restoreValues();
}
bool BasicSettingsAccessor::writeFile(const FileName &path, const QVariantMap &data, QWidget *parent) const
{
if (data.isEmpty())
return false;
if (!m_writer || m_writer->fileName() != path)
m_writer = std::make_unique<PersistentSettingsWriter>(path, m_docType);
return m_writer->save(data, parent);
}
FileName BasicSettingsAccessor::baseFilePath() const
{
return m_baseFilePath;
}
// -----------------------------------------------------------------------------
// VersionUpgrader:
// -----------------------------------------------------------------------------
VersionUpgrader::VersionUpgrader(const int version, const QString &extension) :
m_version(version), m_extension(extension)
{ }
int VersionUpgrader::version() const
{
QTC_CHECK(m_version >= 0);
return m_version;
}
QString VersionUpgrader::backupExtension() const
{
QTC_CHECK(!m_extension.isEmpty());
return m_extension;
QTC_CHECK(!docType.isEmpty());
QTC_CHECK(!displayName.isEmpty());
QTC_CHECK(!applicationDisplayName.isEmpty());
}
/*!
* Performs a simple renaming of the listed keys in \a changes recursively on \a map.
* Restore settings from disk and report any issues in a message box centered on \a parent.
*/
QVariantMap VersionUpgrader::renameKeys(const QList<Change> &changes, QVariantMap map) const
QVariantMap BasicSettingsAccessor::restoreSettings(QWidget *parent) const
{
foreach (const Change &change, changes) {
QVariantMap::iterator oldSetting = map.find(change.first);
if (oldSetting != map.end()) {
map.insert(change.second, oldSetting.value());
map.erase(oldSetting);
}
QTC_ASSERT(!m_baseFilePath.isEmpty(), return QVariantMap());
const RestoreData result = readData(m_baseFilePath, parent);
const ProceedInfo pi = result.issue ? reportIssues(result.issue.value(), result.path, parent) : ProceedInfo::Continue;
return pi == ProceedInfo::DiscardAndContinue ? QVariantMap() : result.data;
}
/*!
* Save \a data to disk and report any issues in a message box centered on \a parent.
*/
bool BasicSettingsAccessor::saveSettings(const QVariantMap &data, QWidget *parent) const
{
const optional<Issue> result = writeData(m_baseFilePath, data);
const ProceedInfo pi = result ? reportIssues(result.value(), m_baseFilePath, parent) : ProceedInfo::Continue;
return pi == ProceedInfo::Continue;
}
/*!
* Read data from \a path. Do all the necessary postprocessing of the data.
*/
BasicSettingsAccessor::RestoreData BasicSettingsAccessor::readData(const FileName &path,
QWidget *parent) const
{
Q_UNUSED(parent);
RestoreData result = readFile(path);
if (!result.data.isEmpty())
result.data = preprocessReadSettings(result.data);
return result;
}
/*!
* Store the \a data in \a path on disk. Do all the necessary preprocessing of the data.
*/
Utils::optional<BasicSettingsAccessor::Issue>
BasicSettingsAccessor::writeData(const FileName &path, const QVariantMap &data) const
{
return writeFile(path, prepareToWriteSettings(data));
}
/*!
* Read a file at \a path from disk and extract the data into a RestoreData set.
*
* This method does not do *any* processing of the file contents.
*/
BasicSettingsAccessor::RestoreData BasicSettingsAccessor::readFile(const FileName &path) const
{
PersistentSettingsReader reader;
if (!reader.load(path)) {
return RestoreData(Issue(QCoreApplication::translate("Utils::SettingsAccessor", "Failed to Read File"),
QCoreApplication::translate("Utils::SettingsAccessor", "Could not open \"%1\".")
.arg(path.toUserOutput())));
}
QVariantMap::iterator i = map.begin();
while (i != map.end()) {
QVariant v = i.value();
if (v.type() == QVariant::Map)
i.value() = renameKeys(changes, v.toMap());
return RestoreData(path, reader.restoreValues());
}
++i;
/*!
* Write a file at \a path to disk and store the \a data in it.
*
* This method does not do *any* processing of the file contents.
*/
Utils::optional<BasicSettingsAccessor::Issue>
BasicSettingsAccessor::writeFile(const FileName &path, const QVariantMap &data) const
{
if (data.isEmpty()) {
return Issue(QCoreApplication::translate("Utils::SettingsAccessor", "Failed to Write File"),
QCoreApplication::translate("Utils::SettingsAccessor", "There was nothing to write."));
}
return map;
QString errorMessage;
if (!m_writer || m_writer->fileName() != path)
m_writer = std::make_unique<PersistentSettingsWriter>(path, docType);
if (!m_writer->save(data, &errorMessage)) {
return Issue(QCoreApplication::translate("Utils::SettingsAccessor", "Failed to Write File"),
errorMessage);
}
return {};
}
BasicSettingsAccessor::ProceedInfo
BasicSettingsAccessor::reportIssues(const BasicSettingsAccessor::Issue &issue, const FileName &path,
QWidget *parent) const
{
if (!path.exists())
return Continue;
const QMessageBox::Icon icon
= issue.buttons.count() > 1 ? QMessageBox::Question : QMessageBox::Information;
const QMessageBox::StandardButtons buttons = issue.allButtons();
QTC_ASSERT(buttons != QMessageBox::NoButton, return Continue);
QMessageBox msgBox(icon, issue.title, issue.message, buttons, parent);
if (issue.defaultButton != QMessageBox::NoButton)
msgBox.setDefaultButton(issue.defaultButton);
if (issue.escapeButton != QMessageBox::NoButton)
msgBox.setEscapeButton(issue.escapeButton);
int boxAction = msgBox.exec();
return issue.buttons.value(static_cast<QMessageBox::StandardButton>(boxAction));
}
/*!
* This method is called right after reading data from disk and modifies \a data.
*/
QVariantMap BasicSettingsAccessor::preprocessReadSettings(const QVariantMap &data) const
{
return data;
}
/*!
* This method is called right before writing data to disk and modifies \a data.
*/
QVariantMap BasicSettingsAccessor::prepareToWriteSettings(const QVariantMap &data) const
{
return data;
}
// --------------------------------------------------------------------
@@ -271,16 +331,13 @@ public:
return m_upgraders[static_cast<size_t>(pos)].get();
return nullptr;
}
Settings bestSettings(const SettingsAccessor *accessor, const FileNameList &pathList);
BasicSettingsAccessor::RestoreData bestSettings(const SettingsAccessor *accessor, const FileNameList &pathList, QWidget *parent);
std::vector<std::unique_ptr<VersionUpgrader>> m_upgraders;
std::unique_ptr<PersistentSettingsWriter> m_writer;
QByteArray m_settingsId;
QString m_displayName;
QString m_applicationDisplayName;
QString m_userSuffix;
QString m_sharedSuffix;
std::unique_ptr<BasicSettingsAccessor> m_sharedFile;
};
// Return path to shared directory for .user files, create if necessary.
@@ -355,16 +412,68 @@ static FileName userFilePath(const Utils::FileName &projectFilePath, const QStri
return result;
}
// --------------------------------------------------------------------
// VersionUpgrader:
// --------------------------------------------------------------------
VersionUpgrader::VersionUpgrader(const int version, const QString &extension) :
m_version(version), m_extension(extension)
{
QTC_CHECK(m_version >= 0);
}
int VersionUpgrader::version() const
{
return m_version;
}
QString VersionUpgrader::backupExtension() const
{
QTC_CHECK(!m_extension.isEmpty());
return m_extension;
}
/*!
* Performs a simple renaming of the listed keys in \a changes recursively on \a map.
*/
QVariantMap VersionUpgrader::renameKeys(const QList<Change> &changes, QVariantMap map) const
{
foreach (const Change &change, changes) {
QVariantMap::iterator oldSetting = map.find(change.first);
if (oldSetting != map.end()) {
map.insert(change.second, oldSetting.value());
map.erase(oldSetting);
}
}
QVariantMap::iterator i = map.begin();
while (i != map.end()) {
QVariant v = i.value();
if (v.type() == QVariant::Map)
i.value() = renameKeys(changes, v.toMap());
++i;
}
return map;
}
// -----------------------------------------------------------------------------
// SettingsAccessor:
// -----------------------------------------------------------------------------
SettingsAccessor::SettingsAccessor(const Utils::FileName &baseFile, const QString &docType) :
BasicSettingsAccessor(baseFile, docType),
SettingsAccessor::SettingsAccessor(const Utils::FileName &baseFile, const QString &docType,
const QString &displayName, const QString &appDisplayName) :
BasicSettingsAccessor(docType, displayName, appDisplayName),
d(new SettingsAccessorPrivate)
{
d->m_userSuffix = generateSuffix(QString::fromLocal8Bit(qgetenv("QTC_EXTENSION")), ".user");
d->m_sharedSuffix = generateSuffix(QString::fromLocal8Bit(qgetenv("QTC_SHARED_EXTENSION")), ".shared");
Utils::FileName baseFilePath = userFilePath(baseFile, generateSuffix(QString::fromLocal8Bit(qgetenv("QTC_EXTENSION")), ".user"));
setBaseFilePath(baseFilePath);
Utils::FileName sharedFilePath = baseFile;
sharedFilePath.appendString(generateSuffix(QString::fromLocal8Bit(qgetenv("QTC_SHARED_EXTENSION")), ".shared"));
d->m_sharedFile = std::make_unique<BasicSettingsAccessor>(docType, displayName, appDisplayName);
d->m_sharedFile->setBaseFilePath(sharedFilePath);
}
SettingsAccessor::~SettingsAccessor()
@@ -396,19 +505,6 @@ QVariantMap SettingsAccessor::setVersionInMap(const QVariantMap &data, int versi
return result;
}
/*!
* Run directly after reading the \a data.
*
* This method is called right after reading the data before any attempt at interpreting the data
* is made.
*
* Returns the prepared data.
*/
QVariantMap SettingsAccessor::prepareSettings(const QVariantMap &data) const
{
return data;
}
/*!
* Check which of two sets of data are a better match to load.
*
@@ -480,102 +576,56 @@ QVariantMap SettingsAccessor::upgradeSettings(const QVariantMap &data, int targe
return result;
}
/*!
* Find issues with the settings file and warn the user about them.
*
* \a data is the data from the settings file.
* \a path is the full path to the settings used.
* \a parent is the widget to be set as parent of any dialogs that are opened.
*
* Returns \c true if the settings are not usable anymore and \c false otherwise.
*/
SettingsAccessor::ProceedInfo SettingsAccessor::reportIssues(const QVariantMap &data,
const FileName &path,
QWidget *parent) const
{
if (!path.exists())
return Continue;
const Utils::optional<IssueInfo> issue = findIssues(data, path);
if (!issue)
return Continue;
const IssueInfo &details = issue.value();
const QMessageBox::Icon icon
= details.buttons.count() > 1 ? QMessageBox::Question : QMessageBox::Information;
const QMessageBox::StandardButtons buttons = [&details]()
{
QMessageBox::StandardButtons buttons = QMessageBox::NoButton;
for (const QMessageBox::StandardButton &b : details.buttons.keys())
buttons |= b;
return buttons;
}();
QTC_ASSERT(buttons != QMessageBox::NoButton, return Continue);
QMessageBox msgBox(icon, details.title, details.message, buttons, parent);
if (details.defaultButton != QMessageBox::NoButton)
msgBox.setDefaultButton(details.defaultButton);
if (details.escapeButton != QMessageBox::NoButton)
msgBox.setEscapeButton(details.escapeButton);
int boxAction = msgBox.exec();
return details.buttons.value(static_cast<QMessageBox::StandardButton>(boxAction));
}
/*!
* Checks \a data located at \a path for issues to be displayed with reportIssues.
*
* Returns a IssueInfo object which is then used by reportIssues.
*/
Utils::optional<SettingsAccessor::IssueInfo>
Utils::optional<SettingsAccessor::Issue>
SettingsAccessor::findIssues(const QVariantMap &data, const FileName &path) const
{
const FileName defaultSettingsPath = userFilePath(baseFilePath(), d->m_userSuffix);
const int version = versionFromMap(data);
if (data.isEmpty() || version < firstSupportedVersion() || version > currentVersion()) {
IssueInfo result;
result.title = QApplication::translate("Utils::SettingsAccessor", "No Valid Settings Found");
result.message = QApplication::translate("Utils::SettingsAccessor",
"<p>No valid settings file could be found.</p>"
"<p>All settings files found in directory \"%1\" "
"were either too new or too old to be read.</p>")
.arg(path.toUserOutput());
Issue result(QApplication::translate("Utils::SettingsAccessor", "No Valid Settings Found"),
QApplication::translate("Utils::SettingsAccessor",
"<p>No valid settings file could be found.</p>"
"<p>All settings files found in directory \"%1\" "
"were either too new or too old to be read.</p>")
.arg(path.toUserOutput()));
result.buttons.insert(QMessageBox::Ok, DiscardAndContinue);
return result;
}
if ((path != defaultSettingsPath) && (version < currentVersion())) {
IssueInfo result;
result.title = QApplication::translate("Utils::SettingsAccessor", "Using Old Settings");
result.message = QApplication::translate("Utils::SettingsAccessor",
"<p>The versioned backup \"%1\" of the settings "
"file is used, because the non-versioned file was "
"created by an incompatible version of %2.</p>"
"<p>Settings changes made since the last time this "
"version of %2 was used are ignored, and "
"changes made now will <b>not</b> be propagated to "
"the newer version.</p>").arg(path.toUserOutput())
.arg(d->m_applicationDisplayName);
if ((path != baseFilePath()) && (version < currentVersion())) {
Issue result(QApplication::translate("Utils::SettingsAccessor", "Using Old Settings"),
QApplication::translate("Utils::SettingsAccessor",
"<p>The versioned backup \"%1\" of the settings "
"file is used, because the non-versioned file was "
"created by an incompatible version of %2.</p>"
"<p>Settings changes made since the last time this "
"version of %2 was used are ignored, and "
"changes made now will <b>not</b> be propagated to "
"the newer version.</p>")
.arg(path.toUserOutput())
.arg(applicationDisplayName));
result.buttons.insert(QMessageBox::Ok, Continue);
return result;
}
const QByteArray readId = settingsIdFromMap(data);
if (!readId.isEmpty() && readId != settingsId()) {
IssueInfo result;
result.title = differentEnvironmentMsg(d->m_displayName);
result.message = QApplication::translate("Utils::EnvironmentIdAccessor",
"<p>No .user settings file created by this instance "
"of %1 was found.</p>"
"<p>Did you work with this project on another machine or "
"using a different settings path before?</p>"
"<p>Do you still want to load the settings file \"%2\"?</p>")
.arg(d->m_applicationDisplayName)
.arg(path.toUserOutput());
Issue result(differentEnvironmentMsg(displayName),
QApplication::translate("Utils::EnvironmentIdAccessor",
"<p>No .user settings file created by this instance "
"of %1 was found.</p>"
"<p>Did you work with this project on another machine or "
"using a different settings path before?</p>"
"<p>Do you still want to load the settings file \"%2\"?</p>")
.arg(applicationDisplayName)
.arg(path.toUserOutput()));
result.defaultButton = QMessageBox::No;
result.escapeButton = QMessageBox::No;
result.buttons.insert(QMessageBox::Yes, SettingsAccessor::Continue);
result.buttons.insert(QMessageBox::No, SettingsAccessor::DiscardAndContinue);
result.buttons.insert(QMessageBox::Yes, Continue);
result.buttons.insert(QMessageBox::No, DiscardAndContinue);
return result;
}
@@ -604,16 +654,7 @@ QByteArray SettingsAccessor::settingsIdFromMap(const QVariantMap &data)
return data.value(SETTINGS_ID_KEY).toByteArray();
}
QVariantMap SettingsAccessor::restoreSettings(QWidget *parent) const
{
QTC_ASSERT(d->lastVersion() >= 0, return QVariantMap());
const QVariantMap userSettings = readUserSettings(parent);
const QVariantMap sharedSettings = readSharedSettings(parent);
return mergeSettings(userSettings, sharedSettings);
}
QVariantMap SettingsAccessor::prepareToSaveSettings(const QVariantMap &data) const
QVariantMap SettingsAccessor::prepareToWriteSettings(const QVariantMap &data) const
{
QVariantMap tmp = data;
const QVariant &shared = retrieveSharedSettings();
@@ -626,19 +667,6 @@ QVariantMap SettingsAccessor::prepareToSaveSettings(const QVariantMap &data) con
return tmp;
}
bool SettingsAccessor::saveSettings(const QVariantMap &map, QWidget *parent) const
{
if (map.isEmpty())
return false;
backupUserFile();
QVariantMap data = prepareToSaveSettings(map);
FileName path = FileName::fromString(defaultFileName(d->m_userSuffix));
return writeFile(path, data, parent);
}
bool SettingsAccessor::addVersionUpgrader(std::unique_ptr<VersionUpgrader> upgrader)
{
QTC_ASSERT(upgrader.get(), return false);
@@ -651,29 +679,51 @@ bool SettingsAccessor::addVersionUpgrader(std::unique_ptr<VersionUpgrader> upgra
return true;
}
BasicSettingsAccessor::RestoreData SettingsAccessor::readData(const FileName &path,
QWidget *parent) const
{
Q_UNUSED(path); // FIXME: This is wrong!
// FIXME: Do better error handling:
QTC_ASSERT(d->lastVersion() >= 0, return RestoreData("SETUP FAILED", "SETUP FAILED"));
RestoreData userSettings = readUserSettings(parent);
if (userSettings.issue && reportIssues(userSettings.issue.value(), userSettings.path, parent) == DiscardAndContinue)
userSettings.data.clear();
RestoreData sharedSettings = readSharedSettings(parent);
if (sharedSettings.issue && reportIssues(sharedSettings.issue.value(), sharedSettings.path, parent) == DiscardAndContinue)
sharedSettings.data.clear();
RestoreData mergedSettings = RestoreData(userSettings.path,
mergeSettings(userSettings.data, sharedSettings.data));
mergedSettings.issue = findIssues(mergedSettings.data, mergedSettings.path);
return mergedSettings;
}
Utils::optional<BasicSettingsAccessor::Issue> SettingsAccessor::writeData(const FileName &path,
const QVariantMap &data) const
{
if (data.isEmpty())
return {};
backupUserFile();
return BasicSettingsAccessor::writeData(path, data);
}
void SettingsAccessor::setSettingsId(const QByteArray &id)
{
d->m_settingsId = id;
}
void SettingsAccessor::setDisplayName(const QString &dn)
{
d->m_displayName = dn;
}
void SettingsAccessor::setApplicationDisplayName(const QString &dn)
{
d->m_applicationDisplayName = dn;
}
/* Will always return the default name first (if applicable) */
FileNameList SettingsAccessor::settingsFiles(const QString &suffix) const
FileNameList SettingsAccessor::settingsFiles() const
{
FileNameList result;
QFileInfoList list;
const QFileInfo pfi = baseFilePath().toFileInfo();
const QStringList filter(pfi.fileName() + suffix + '*');
const QStringList filter(pfi.fileName() + '*');
if (!sharedUserFileDir().isEmpty()) {
const QString sharedPath = sharedUserFileDir() + '/' + makeRelative(pfi.absolutePath());
@@ -684,7 +734,7 @@ FileNameList SettingsAccessor::settingsFiles(const QString &suffix) const
foreach (const QFileInfo &fi, list) {
const FileName path = FileName::fromString(fi.absoluteFilePath());
if (!result.contains(path)) {
if (path.endsWith(suffix))
if (path == baseFilePath())
result.prepend(path);
else
result.append(path);
@@ -699,16 +749,6 @@ QByteArray SettingsAccessor::settingsId() const
return d->m_settingsId;
}
QString SettingsAccessor::displayName() const
{
return d->m_displayName;
}
QString SettingsAccessor::defaultFileName(const QString &suffix) const
{
return userFilePath(baseFilePath(), suffix).toString();
}
int SettingsAccessor::currentVersion() const
{
return d->currentVersion();
@@ -721,7 +761,7 @@ int SettingsAccessor::firstSupportedVersion() const
FileName SettingsAccessor::backupName(const QVariantMap &data) const
{
QString backupName = defaultFileName(d->m_userSuffix);
QString backupName = baseFilePath().toString();
const QByteArray oldEnvironmentId = settingsIdFromMap(data);
if (!oldEnvironmentId.isEmpty() && oldEnvironmentId != settingsId())
backupName += '.' + QString::fromLatin1(oldEnvironmentId).mid(1, 7);
@@ -738,89 +778,71 @@ FileName SettingsAccessor::backupName(const QVariantMap &data) const
void SettingsAccessor::backupUserFile() const
{
SettingsAccessorPrivate::Settings oldSettings;
oldSettings.path = FileName::fromString(defaultFileName(d->m_userSuffix));
oldSettings.map = readFile(oldSettings.path);
if (oldSettings.map.isEmpty())
RestoreData oldSettings = BasicSettingsAccessor::readFile(baseFilePath());
if (oldSettings.data.isEmpty())
return;
// Do we need to do a backup?
const QString origName = oldSettings.path.toString();
QString backupFileName = backupName(oldSettings.map).toString();
QString backupFileName = backupName(oldSettings.data).toString();
if (backupFileName != origName)
QFile::copy(origName, backupFileName);
}
QVariantMap SettingsAccessor::readUserSettings(QWidget *parent) const
SettingsAccessor::RestoreData SettingsAccessor::readUserSettings(QWidget *parent) const
{
SettingsAccessorPrivate::Settings result;
FileNameList fileList = settingsFiles(d->m_userSuffix);
FileNameList fileList = settingsFiles();
if (fileList.isEmpty()) // No settings found at all.
return result.map;
return RestoreData(baseFilePath(), QVariantMap());
result = d->bestSettings(this, fileList);
RestoreData result = d->bestSettings(this, fileList, parent);
if (result.path.isEmpty())
result.path = baseFilePath().parentDir();
ProceedInfo proceed = reportIssues(result.map, result.path, parent);
if (proceed == DiscardAndContinue)
return QVariantMap();
return result.map;
return result;
}
QVariantMap SettingsAccessor::readSharedSettings(QWidget *parent) const
SettingsAccessor::RestoreData SettingsAccessor::readSharedSettings(QWidget *parent) const
{
SettingsAccessorPrivate::Settings sharedSettings;
QString fn = baseFilePath().toString() + d->m_sharedSuffix;
sharedSettings.path = FileName::fromString(fn);
sharedSettings.map = readFile(sharedSettings.path);
RestoreData sharedSettings = d->m_sharedFile->readData(d->m_sharedFile->baseFilePath(), parent);
if (versionFromMap(sharedSettings.map) > currentVersion()) {
if (versionFromMap(sharedSettings.data) > currentVersion()) {
// The shared file version is newer than Creator... If we have valid user
// settings we prompt the user whether we could try an *unsupported* update.
// This makes sense since the merging operation will only replace shared settings
// that perfectly match corresponding user ones. If we don't have valid user
// settings to compare against, there's nothing we can do.
QMessageBox msgBox(
QMessageBox::Question,
QApplication::translate("Utils::SettingsAccessor",
"Unsupported Shared Settings File"),
QApplication::translate("Utils::SettingsAccessor",
"The version of your .shared file is not "
"supported by %1. "
"Do you want to try loading it anyway?")
.arg(d->m_applicationDisplayName),
QMessageBox::Yes | QMessageBox::No,
parent);
msgBox.setDefaultButton(QMessageBox::No);
msgBox.setEscapeButton(QMessageBox::No);
if (msgBox.exec() == QMessageBox::No)
sharedSettings.map.clear();
else
sharedSettings.map = setVersionInMap(sharedSettings.map, currentVersion());
sharedSettings.issue = Issue(QApplication::translate("Utils::SettingsAccessor",
"Unsupported Shared Settings File"),
QApplication::translate("Utils::SettingsAccessor",
"The version of your .shared file is not "
"supported by %1. "
"Do you want to try loading it anyway?"));
sharedSettings.issue->buttons.insert(QMessageBox::Yes, Continue);
sharedSettings.issue->buttons.insert(QMessageBox::No, DiscardAndContinue);
sharedSettings.issue->defaultButton = QMessageBox::No;
sharedSettings.issue->escapeButton = QMessageBox::No;
}
return sharedSettings.map;
return sharedSettings;
}
SettingsAccessorPrivate::Settings SettingsAccessorPrivate::bestSettings(const SettingsAccessor *accessor,
const FileNameList &pathList)
SettingsAccessor::RestoreData SettingsAccessorPrivate::bestSettings(const SettingsAccessor *accessor,
const FileNameList &pathList,
QWidget *parent)
{
Settings bestMatch;
SettingsAccessor::RestoreData bestMatch;
foreach (const FileName &path, pathList) {
const QVariantMap tmp = accessor->prepareSettings(accessor->readFile(path));
const SettingsAccessor::RestoreData tmp = accessor->BasicSettingsAccessor::readData(path, parent);
if (accessor->isBetterMatch(bestMatch.map, tmp)) {
bestMatch.path = path;
bestMatch.map = tmp;
}
if (accessor->isBetterMatch(bestMatch.data, tmp.data))
bestMatch = tmp;
}
return bestMatch;
}
QVariantMap SettingsAccessor::mergeSettings(const QVariantMap &userMap,
const QVariantMap &sharedMap) const
QVariantMap
SettingsAccessor::mergeSettings(const QVariantMap &userMap, const QVariantMap &sharedMap) const
{
QVariantMap newUser = userMap;
QVariantMap newShared = sharedMap;

View File

@@ -35,30 +35,73 @@
#include <QMessageBox>
#include <QVariantMap>
#include <memory>
namespace Utils {
// --------------------------------------------------------------------
// BasicSettingsAccessor:
// --------------------------------------------------------------------
// Read/write files incl. error handling suitable for the UI:
class QTCREATOR_UTILS_EXPORT BasicSettingsAccessor
{
public:
BasicSettingsAccessor(const Utils::FileName &baseFilePath, const QString &docType);
virtual ~BasicSettingsAccessor();
BasicSettingsAccessor(const QString &docType, const QString &displayName,
const QString &applicationDisplayName);
virtual ~BasicSettingsAccessor() = default;
virtual QVariantMap restoreSettings(QWidget *parent) const;
virtual bool saveSettings(const QVariantMap &data, QWidget *parent) const;
enum ProceedInfo { Continue, DiscardAndContinue };
typedef QHash<QMessageBox::StandardButton, ProceedInfo> ButtonMap;
class Issue {
public:
Issue(const QString &title, const QString &message) : title{title}, message{message} { }
QMessageBox::StandardButtons allButtons() const;
QString title;
QString message;
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton;
QMessageBox::StandardButton escapeButton = QMessageBox::Ok;
QHash<QMessageBox::StandardButton, ProceedInfo> buttons = {{QMessageBox::Ok, ProceedInfo::Continue}};
};
class RestoreData {
public:
RestoreData() = default;
RestoreData(const Utils::FileName &path, const QVariantMap &data) : path{path}, data{data} { }
RestoreData(const QString &title, const QString &message) : RestoreData(Issue(title, message)) { }
RestoreData(const Issue &issue) : issue{issue} { }
Utils::FileName path;
QVariantMap data;
Utils::optional<Issue> issue;
};
QVariantMap restoreSettings(QWidget *parent) const;
bool saveSettings(const QVariantMap &data, QWidget *parent) const;
const QString docType;
const QString displayName;
const QString applicationDisplayName;
void setBaseFilePath(const Utils::FileName &baseFilePath) { m_baseFilePath = baseFilePath; }
Utils::FileName baseFilePath() const { return m_baseFilePath; }
virtual RestoreData readData(const Utils::FileName &path, QWidget *parent) const;
virtual Utils::optional<Issue> writeData(const Utils::FileName &path, const QVariantMap &data) const;
protected:
QVariantMap readFile(const Utils::FileName &path) const;
bool writeFile(const Utils::FileName &path, const QVariantMap &data, QWidget *parent) const;
// Report errors:
ProceedInfo reportIssues(const Issue &issue, const FileName &path, QWidget *parent) const;
Utils::FileName baseFilePath() const;
virtual QVariantMap preprocessReadSettings(const QVariantMap &data) const;
virtual QVariantMap prepareToWriteSettings(const QVariantMap &data) const;
RestoreData readFile(const Utils::FileName &path) const;
Utils::optional<Issue> writeFile(const Utils::FileName &path, const QVariantMap &data) const;
private:
const Utils::FileName m_baseFilePath;
const QString m_docType;
Utils::FileName m_baseFilePath;
mutable std::unique_ptr<PersistentSettingsWriter> m_writer;
};
@@ -92,12 +135,10 @@ class SettingsAccessorPrivate;
class QTCREATOR_UTILS_EXPORT SettingsAccessor : public BasicSettingsAccessor
{
public:
explicit SettingsAccessor(const Utils::FileName &baseFile, const QString &docType);
explicit SettingsAccessor(const Utils::FileName &baseFile, const QString &docType,
const QString &displayName, const QString &appDisplayName);
~SettingsAccessor() override;
QVariantMap restoreSettings(QWidget *parent) const override;
bool saveSettings(const QVariantMap &data, QWidget *parent) const override;
static QVariantMap setVersionInMap(const QVariantMap &data, int version);
static int versionFromMap(const QVariantMap &data);
static int originalVersionFromMap(const QVariantMap &data);
@@ -108,51 +149,35 @@ public:
bool addVersionUpgrader(std::unique_ptr<VersionUpgrader> upgrader);
enum ProceedInfo { Continue, DiscardAndContinue };
typedef QHash<QMessageBox::StandardButton, ProceedInfo> ButtonMap;
class IssueInfo {
public:
QString title;
QString message;
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton;
QMessageBox::StandardButton escapeButton = QMessageBox::NoButton;
QHash<QMessageBox::StandardButton, ProceedInfo> buttons;
};
protected:
RestoreData readData(const Utils::FileName &path, QWidget *parent) const final;
Utils::optional<Issue> writeData(const Utils::FileName &path, const QVariantMap &data) const final;
void setSettingsId(const QByteArray &id);
void setDisplayName(const QString &dn);
void setApplicationDisplayName(const QString &dn);
QVariantMap upgradeSettings(const QVariantMap &data) const;
QVariantMap upgradeSettings(const QVariantMap &data, const int targetVersion) const;
ProceedInfo reportIssues(const QVariantMap &data, const Utils::FileName &path, QWidget *parent) const;
virtual QVariantMap prepareSettings(const QVariantMap &data) const;
virtual QVariantMap prepareToSaveSettings(const QVariantMap &data) const;
QVariantMap prepareToWriteSettings(const QVariantMap &data) const override;
virtual bool isBetterMatch(const QVariantMap &origData, const QVariantMap &newData) const;
virtual bool isValidVersionAndId(const int version, const QByteArray &id) const;
virtual Utils::FileName backupName(const QVariantMap &data) const;
virtual Utils::optional<IssueInfo> findIssues(const QVariantMap &data,
const Utils::FileName &path) const;
QVariantMap mergeSettings(const QVariantMap &userMap, const QVariantMap &sharedMap) const;
virtual void storeSharedSettings(const QVariantMap &data) const;
virtual QVariant retrieveSharedSettings() const;
QVariantMap mergeSettings(const QVariantMap &userMap, const QVariantMap &sharedMap) const;
Utils::optional<Issue> findIssues(const QVariantMap &data, const Utils::FileName &path) const;
private:
Utils::FileNameList settingsFiles(const QString &suffix) const;
Utils::FileNameList settingsFiles() const;
QByteArray settingsId() const;
QString displayName() const;
QString defaultFileName(const QString &suffix) const;
void backupUserFile() const;
QVariantMap readUserSettings(QWidget *parent) const;
QVariantMap readSharedSettings(QWidget *parent) const;
RestoreData readUserSettings(QWidget *parent) const;
RestoreData readSharedSettings(QWidget *parent) const;
static QByteArray settingsIdFromMap(const QVariantMap &data);
static QString differentEnvironmentMsg(const QString &projectName);

View File

@@ -33,10 +33,6 @@
#include <iterator>
#include <ostream>
#ifdef UNIT_TESTS
#include <gtest/gtest.h>
#endif
namespace Utils {
template <uint Size>
@@ -235,22 +231,6 @@ QDataStream &operator>>(QDataStream &in, vector<Type> &vector)
return in;
}
#ifdef UNIT_TESTS
template <typename T>
ostream &operator<<(ostream &out, const vector<T> &vector)
{
out << "[";
ostream_iterator<string> outIterator(out, ", ");
for (const auto &entry : vector)
outIterator = ::testing::PrintToString(entry);
out << "]";
return out;
}
#else
template <typename T>
ostream &operator<<(ostream &out, const vector<T> &vector)
{
@@ -262,7 +242,6 @@ ostream &operator<<(ostream &out, const vector<T> &vector)
return out;
}
#endif
} // namespace std

View File

@@ -27,6 +27,7 @@
#include "gtestresult.h"
#include "../testtreemodel.h"
#include "../testtreeitem.h"
#include "utils/hostosinfo.h"
#include <QDir>
#include <QFileInfo>
@@ -47,6 +48,15 @@ GTestOutputReader::GTestOutputReader(const QFutureInterface<TestResultPtr> &futu
, m_executable(testApplication ? testApplication->program() : QString())
, m_projectFile(projectFile)
{
// on Windows abort() will result in normal termination, but exit code will be set to 3
if (Utils::HostOsInfo::isWindowsHost()) {
connect(m_testApplication,
static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
this, [this] (int exitCode, QProcess::ExitStatus /*exitStatus*/) {
if (exitCode == 3)
reportCrash();
});
}
}
void GTestOutputReader::processOutput(const QByteArray &outputLine)
@@ -92,15 +102,15 @@ void GTestOutputReader::processOutput(const QByteArray &outputLine)
}
if (testEnds.exactMatch(line)) {
GTestResult *testResult = createDefaultResult();
TestResultPtr testResult = createDefaultResult();
testResult->setResult(Result::MessageTestCaseEnd);
testResult->setDescription(tr("Test execution took %1").arg(testEnds.cap(2)));
reportResult(TestResultPtr(testResult));
reportResult(testResult);
m_currentTestName.clear();
m_currentTestSet.clear();
} else if (newTestStarts.exactMatch(line)) {
setCurrentTestName(newTestStarts.cap(1));
TestResultPtr testResult = TestResultPtr(createDefaultResult());
TestResultPtr testResult = createDefaultResult();
testResult->setResult(Result::MessageTestCaseStart);
if (m_iteration > 1) {
testResult->setDescription(tr("Repeating test case %1 (iteration %2)")
@@ -117,18 +127,18 @@ void GTestOutputReader::processOutput(const QByteArray &outputLine)
reportResult(testResult);
m_description.clear();
} else if (testSetSuccess.exactMatch(line)) {
GTestResult *testResult = createDefaultResult();
TestResultPtr testResult = createDefaultResult();
testResult->setResult(Result::Pass);
testResult->setDescription(m_description);
reportResult(TestResultPtr(testResult));
reportResult(testResult);
m_description.clear();
testResult = createDefaultResult();
testResult->setResult(Result::MessageInternal);
testResult->setDescription(tr("Execution took %1.").arg(testSetSuccess.cap(2)));
reportResult(TestResultPtr(testResult));
reportResult(testResult);
m_futureInterface.setProgressValue(m_futureInterface.progressValue() + 1);
} else if (testSetFail.exactMatch(line)) {
GTestResult *testResult = createDefaultResult();
TestResultPtr testResult = createDefaultResult();
testResult->setResult(Result::Fail);
m_description.chop(1);
testResult->setDescription(m_description);
@@ -149,27 +159,17 @@ void GTestOutputReader::processOutput(const QByteArray &outputLine)
}
}
}
reportResult(TestResultPtr(testResult));
reportResult(testResult);
m_description.clear();
testResult = createDefaultResult();
testResult->setResult(Result::MessageInternal);
testResult->setDescription(tr("Execution took %1.").arg(testSetFail.cap(2)));
reportResult(TestResultPtr(testResult));
reportResult(testResult);
m_futureInterface.setProgressValue(m_futureInterface.progressValue() + 1);
}
}
void GTestOutputReader::setCurrentTestSet(const QString &testSet)
{
m_currentTestSet = testSet;
}
void GTestOutputReader::setCurrentTestName(const QString &testName)
{
m_currentTestName = testName;
}
GTestResult *GTestOutputReader::createDefaultResult() const
TestResultPtr GTestOutputReader::createDefaultResult() const
{
GTestResult *result = new GTestResult(m_executable, m_projectFile, m_currentTestName);
result->setTestSetName(m_currentTestSet);
@@ -182,7 +182,17 @@ GTestResult *GTestOutputReader::createDefaultResult() const
result->setLine(static_cast<int>(testItem->line()));
}
return result;
return TestResultPtr(result);
}
void GTestOutputReader::setCurrentTestSet(const QString &testSet)
{
m_currentTestSet = testSet;
}
void GTestOutputReader::setCurrentTestName(const QString &testName)
{
m_currentTestName = testName;
}
} // namespace Internal

View File

@@ -43,14 +43,13 @@ public:
GTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication, const QString &buildDirectory,
const QString &projectFile);
protected:
void processOutput(const QByteArray &outputLine) override;
TestResultPtr createDefaultResult() const override;
private:
void setCurrentTestSet(const QString &testSet);
void setCurrentTestName(const QString &testName);
GTestResult *createDefaultResult() const;
QString m_executable;
QString m_projectFile;

View File

@@ -26,6 +26,7 @@
#include "gtesttreeitem.h"
#include "gtestconfiguration.h"
#include "gtestparser.h"
#include "../testframeworkmanager.h"
#include <cpptools/cppmodelmanager.h>
#include <projectexplorer/session.h>
@@ -59,6 +60,7 @@ QVariant GTestTreeItem::data(int column, int role) const
case Qt::CheckStateRole:
switch (type()) {
case Root:
case GroupNode:
case TestCase:
case TestFunctionOrSet:
return checked();
@@ -237,6 +239,22 @@ TestTreeItem *GTestTreeItem::find(const TestParseResult *result)
states |= GTestTreeItem::Typed;
switch (type()) {
case Root:
if (TestFrameworkManager::instance()->groupingEnabled(result->frameworkId)) {
const QFileInfo fileInfo(parseResult->fileName);
const QFileInfo base(fileInfo.absolutePath());
for (int row = 0; row < childCount(); ++row) {
GTestTreeItem *group = static_cast<GTestTreeItem *>(childAt(row));
if (group->filePath() != base.absoluteFilePath())
continue;
if (auto groupChild = group->findChildByNameStateAndFile(parseResult->name, states,
parseResult->proFile)) {
return groupChild;
}
}
return nullptr;
}
return findChildByNameStateAndFile(parseResult->name, states, parseResult->proFile);
case GroupNode:
return findChildByNameStateAndFile(parseResult->name, states, parseResult->proFile);
case TestCase:
return findChildByNameAndFile(result->name, result->fileName);
@@ -257,6 +275,13 @@ bool GTestTreeItem::modify(const TestParseResult *result)
}
}
TestTreeItem *GTestTreeItem::createParentGroupNode() const
{
const QFileInfo fileInfo(filePath());
const QFileInfo base(fileInfo.absolutePath());
return new GTestTreeItem(base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
}
bool GTestTreeItem::modifyTestSetContent(const GTestParseResult *result)
{
bool hasBeenModified = modifyLineAndColumn(result);

View File

@@ -58,6 +58,7 @@ public:
QList<TestConfiguration *> getSelectedTestConfigurations() const override;
TestTreeItem *find(const TestParseResult *result) override;
bool modify(const TestParseResult *result) override;
TestTreeItem *createParentGroupNode() const override;
void setStates(TestStates states) { m_state = states; }
void setState(TestState state) { m_state |= state; }

View File

@@ -69,6 +69,8 @@ public:
bool active() const { return m_active; }
void setActive(bool active) { m_active = active; }
bool grouping() const { return m_grouping; }
void setGrouping(bool group) { m_grouping = group; }
protected:
virtual ITestParser *createTestParser() const = 0;
@@ -78,6 +80,7 @@ private:
TestTreeItem *m_rootNode = 0;
ITestParser *m_testParser = 0;
bool m_active = false;
bool m_grouping = false;
};
} // namespace Internal

View File

@@ -39,9 +39,10 @@ CppParser::CppParser()
s_parserInstance = this;
}
void CppParser::init(const QStringList &filesToParse)
void CppParser::init(const QStringList &filesToParse, bool fullParse)
{
Q_UNUSED(filesToParse);
Q_UNUSED(fullParse);
m_cppSnapshot = CppTools::CppModelManager::instance()->snapshot();
m_workingCopy = CppTools::CppModelManager::instance()->workingCopy();
}

View File

@@ -61,7 +61,7 @@ class ITestParser
{
public:
virtual ~ITestParser() { }
virtual void init(const QStringList &filesToParse) = 0;
virtual void init(const QStringList &filesToParse, bool fullParse) = 0;
virtual bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
const QString &fileName) = 0;
virtual void release() = 0;
@@ -76,7 +76,7 @@ class CppParser : public ITestParser
{
public:
CppParser();
void init(const QStringList &filesToParse) override;
void init(const QStringList &filesToParse, bool fullParse) override;
static bool selectedForBuilding(const QString &fileName);
static QByteArray getFileContent(const QString &filePath);
void release() override;

View File

@@ -152,6 +152,14 @@ void QtTestOutputReader::processOutput(const QByteArray &outputLine)
}
}
TestResultPtr QtTestOutputReader::createDefaultResult() const
{
QtTestResult *result = new QtTestResult(m_executable, m_projectFile, m_testType, m_className);
result->setFunctionName(m_testCase);
result->setDataTag(m_dataTag);
return TestResultPtr(result);
}
void QtTestOutputReader::processXMLOutput(const QByteArray &outputLine)
{
static QStringList validEndTags = {QStringLiteral("Incident"),
@@ -416,17 +424,9 @@ void QtTestOutputReader::processSummaryFinishOutput()
m_lineNumber = 0;
}
QtTestResult *QtTestOutputReader::createDefaultResult() const
{
QtTestResult *result = new QtTestResult(m_executable, m_projectFile, m_testType, m_className);
result->setFunctionName(m_testCase);
result->setDataTag(m_dataTag);
return result;
}
void QtTestOutputReader::sendCompleteInformation()
{
TestResultPtr testResult = TestResultPtr(createDefaultResult());
TestResultPtr testResult = createDefaultResult();
testResult->setResult(m_result);
if (m_lineNumber) {
@@ -453,7 +453,7 @@ void QtTestOutputReader::sendMessageCurrentTest()
void QtTestOutputReader::sendStartMessage(bool isFunction)
{
TestResultPtr testResult = TestResultPtr(createDefaultResult());
TestResultPtr testResult = createDefaultResult();
testResult->setResult(Result::MessageTestCaseStart);
testResult->setDescription(isFunction ? tr("Executing test function %1").arg(m_testCase)
: tr("Executing test case %1").arg(m_className));
@@ -467,7 +467,7 @@ void QtTestOutputReader::sendStartMessage(bool isFunction)
void QtTestOutputReader::sendFinishMessage(bool isFunction)
{
TestResultPtr testResult = TestResultPtr(createDefaultResult());
TestResultPtr testResult = createDefaultResult();
testResult->setResult(Result::MessageTestCaseEnd);
if (!m_duration.isEmpty()) {
testResult->setDescription(isFunction ? tr("Execution took %1 ms.").arg(m_duration)
@@ -482,18 +482,18 @@ void QtTestOutputReader::sendFinishMessage(bool isFunction)
// TODO factor out tr() strings to avoid duplication (see XML processing of Characters)
void QtTestOutputReader::handleAndSendConfigMessage(const QRegExp &config)
{
QtTestResult *testResult = createDefaultResult();
TestResultPtr testResult = createDefaultResult();
testResult->setResult(Result::MessageInternal);
testResult->setDescription(tr("Qt version: %1").arg(config.cap(3)));
reportResult(TestResultPtr(testResult));
reportResult(testResult);
testResult = createDefaultResult();
testResult->setResult(Result::MessageInternal);
testResult->setDescription(tr("Qt build: %1").arg(config.cap(2)));
reportResult(TestResultPtr(testResult));
reportResult(testResult);
testResult = createDefaultResult();
testResult->setResult(Result::MessageInternal);
testResult->setDescription(tr("QTest version: %1").arg(config.cap(1)));
reportResult(TestResultPtr(testResult));
reportResult(testResult);
}
} // namespace Internal

View File

@@ -50,9 +50,9 @@ public:
QtTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication, const QString &buildDirectory,
const QString &projectFile, OutputMode mode, TestType type);
protected:
void processOutput(const QByteArray &outputLine) override;
TestResultPtr createDefaultResult() const override;
private:
void processXMLOutput(const QByteArray &outputLine);
@@ -61,7 +61,6 @@ private:
void processLocationOutput(const QString &fileWithLine);
void processSummaryFinishOutput();
// helper functions
QtTestResult *createDefaultResult() const;
void sendCompleteInformation();
void sendMessageCurrentTest();
void sendStartMessage(bool isFunction);

View File

@@ -369,11 +369,13 @@ static bool handleQtTest(QFutureInterface<TestParseResultPtr> futureInterface,
return false;
}
void QtTestParser::init(const QStringList &filesToParse)
void QtTestParser::init(const QStringList &filesToParse, bool fullParse)
{
m_testCaseNames = QTestUtils::testCaseNamesForFiles(id(), filesToParse);
m_alternativeFiles = QTestUtils::alternativeFiles(id(), filesToParse);
CppParser::init(filesToParse);
if (!fullParse) { // in a full parse cached information might lead to wrong results
m_testCaseNames = QTestUtils::testCaseNamesForFiles(id(), filesToParse);
m_alternativeFiles = QTestUtils::alternativeFiles(id(), filesToParse);
}
CppParser::init(filesToParse, fullParse);
}
void QtTestParser::release()

View File

@@ -44,7 +44,7 @@ private:
class QtTestParser : public CppParser
{
public:
void init(const QStringList &filesToParse) override;
void init(const QStringList &filesToParse, bool fullParse) override;
void release() override;
bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
const QString &fileName) override;

View File

@@ -26,6 +26,7 @@
#include "qttesttreeitem.h"
#include "qttestconfiguration.h"
#include "qttestparser.h"
#include "../testframeworkmanager.h"
#include <projectexplorer/session.h>
#include <utils/qtcassert.h>
@@ -227,6 +228,19 @@ TestTreeItem *QtTestTreeItem::find(const TestParseResult *result)
switch (type()) {
case Root:
if (TestFrameworkManager::instance()->groupingEnabled(result->frameworkId)) {
const QString path = QFileInfo(result->fileName).absolutePath();
for (int row = 0; row < childCount(); ++row) {
TestTreeItem *group = childItem(row);
if (group->filePath() != path)
continue;
if (auto groupChild = group->findChildByFile(result->fileName))
return groupChild;
}
return nullptr;
}
return findChildByFile(result->fileName);
case GroupNode:
return findChildByFile(result->fileName);
case TestCase: {
const QtTestParseResult *qtResult = static_cast<const QtTestParseResult *>(result);
@@ -259,6 +273,13 @@ bool QtTestTreeItem::modify(const TestParseResult *result)
}
}
TestTreeItem *QtTestTreeItem::createParentGroupNode() const
{
const QFileInfo fileInfo(filePath());
const QFileInfo base(fileInfo.absolutePath());
return new QtTestTreeItem(base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
}
TestTreeItem *QtTestTreeItem::findChildByNameAndInheritance(const QString &name, bool inherited) const
{
return findChildBy([name, inherited](const TestTreeItem *other) -> bool {

View File

@@ -48,6 +48,7 @@ public:
bool modify(const TestParseResult *result) override;
void setInherited(bool inherited) { m_inherited = inherited; }
bool inherited() const { return m_inherited; }
TestTreeItem *createParentGroupNode() const override;
private:
TestTreeItem *findChildByNameAndInheritance(const QString &name, bool inherited) const;
QString nameSuffix() const;

View File

@@ -303,11 +303,12 @@ QuickTestParser::~QuickTestParser()
{
}
void QuickTestParser::init(const QStringList &filesToParse)
void QuickTestParser::init(const QStringList &filesToParse, bool fullParse)
{
m_qmlSnapshot = QmlJSTools::Internal::ModelManager::instance()->snapshot();
m_proFilesForQmlFiles = QuickTestUtils::proFilesForQmlFiles(id(), filesToParse);
CppParser::init(filesToParse);
if (!fullParse) // in a full parse we get the correct entry points by the respective main
m_proFilesForQmlFiles = QuickTestUtils::proFilesForQmlFiles(id(), filesToParse);
CppParser::init(filesToParse, fullParse);
}
void QuickTestParser::release()

View File

@@ -47,7 +47,7 @@ class QuickTestParser : public QObject, public CppParser
public:
QuickTestParser();
virtual ~QuickTestParser();
void init(const QStringList &filesToParse) override;
void init(const QStringList &filesToParse, bool fullParse) override;
void release() override;
bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
const QString &fileName) override;

View File

@@ -26,6 +26,7 @@
#include "quicktesttreeitem.h"
#include "quicktestconfiguration.h"
#include "quicktestparser.h"
#include "../testframeworkmanager.h"
#include <cpptools/cppmodelmanager.h>
#include <projectexplorer/session.h>
@@ -267,7 +268,22 @@ TestTreeItem *QuickTestTreeItem::find(const TestParseResult *result)
switch (type()) {
case Root:
return result->name.isEmpty() ? unnamedQuickTests() : findChildByFile(result->fileName);
if (result->name.isEmpty())
return unnamedQuickTests();
if (TestFrameworkManager::instance()->groupingEnabled(result->frameworkId)) {
const QString path = QFileInfo(result->fileName).absolutePath();
for (int row = 0; row < childCount(); ++row) {
TestTreeItem *group = childItem(row);
if (group->filePath() != path)
continue;
if (auto groupChild = group->findChildByFile(result->fileName))
return groupChild;
}
return nullptr;
}
return findChildByFile(result->fileName);
case GroupNode:
return findChildByFile(result->fileName);
case TestCase:
return name().isEmpty() ? findChildByNameAndFile(result->name, result->fileName)
: findChildByName(result->name);
@@ -303,6 +319,26 @@ bool QuickTestTreeItem::lessThan(const TestTreeItem *other, TestTreeItem::SortMo
return TestTreeItem::lessThan(other, mode);
}
bool QuickTestTreeItem::isGroupNodeFor(const TestTreeItem *other) const
{
QTC_ASSERT(other, return false);
if (other->name().isEmpty()) // unnamed quick tests will not get grouped
return false;
return TestTreeItem::isGroupNodeFor(other);
}
TestTreeItem *QuickTestTreeItem::createParentGroupNode() const
{
if (filePath().isEmpty() || name().isEmpty())
return nullptr;
if (type() == TestFunctionOrSet)
return nullptr;
const QFileInfo fileInfo(filePath());
const QFileInfo base(fileInfo.absolutePath());
return new QuickTestTreeItem(base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
}
QSet<QString> QuickTestTreeItem::internalTargets() const
{
QSet<QString> result;

View File

@@ -47,6 +47,8 @@ public:
TestTreeItem *find(const TestParseResult *result) override;
bool modify(const TestParseResult *result) override;
bool lessThan(const TestTreeItem *other, SortMode mode) const override;
bool isGroupNodeFor(const TestTreeItem *other) const override;
TestTreeItem *createParentGroupNode() const override;
QSet<QString> internalTargets() const override;
private:
TestTreeItem *unnamedQuickTests() const;

View File

@@ -399,7 +399,7 @@ void TestCodeParser::scanForTests(const QStringList &fileList, ITestParser *pars
codeParsers.append(m_testCodeParsers);
qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "StartParsing";
for (ITestParser *parser : codeParsers)
parser->init(list);
parser->init(list, isFullParse);
QFuture<TestParseResultPtr> future = Utils::map(list,
[codeParsers](QFutureInterface<TestParseResultPtr> &fi, const QString &file) {

View File

@@ -94,8 +94,10 @@ void TestFrameworkManager::activateFrameworksFromSettings(QSharedPointer<TestSet
{
FrameworkIterator it = m_registeredFrameworks.begin();
FrameworkIterator end = m_registeredFrameworks.end();
for ( ; it != end; ++it)
for ( ; it != end; ++it) {
it.value()->setActive(settings->frameworks.value(it.key(), false));
it.value()->setGrouping(settings->frameworksGrouping.value(it.key(), false));
}
}
QString TestFrameworkManager::frameworkNameForId(const Core::Id &id) const
@@ -181,6 +183,18 @@ bool TestFrameworkManager::isActive(const Core::Id &frameworkId) const
return framework ? framework->active() : false;
}
bool TestFrameworkManager::groupingEnabled(const Core::Id &frameworkId) const
{
ITestFramework *framework = m_registeredFrameworks.value(frameworkId);
return framework ? framework->grouping() : false;
}
void TestFrameworkManager::setGroupingEnabledFor(const Core::Id &frameworkId, bool enabled)
{
if (ITestFramework *framework = m_registeredFrameworks.value(frameworkId))
framework->setGrouping(enabled);
}
bool TestFrameworkManager::hasActiveFrameworks() const
{
for (ITestFramework *framework : m_registeredFrameworks.values()) {

View File

@@ -63,6 +63,8 @@ public:
QSharedPointer<IFrameworkSettings> settingsForTestFramework(const Core::Id &frameworkId) const;
void synchronizeSettings(QSettings *s);
bool isActive(const Core::Id &frameworkId) const;
bool groupingEnabled(const Core::Id &frameworkId) const;
void setGroupingEnabledFor(const Core::Id &frameworkId, bool enabled);
bool hasActiveFrameworks() const;
private:

View File

@@ -66,6 +66,14 @@ void TestOutputReader::processStdError(const QByteArray &output)
qWarning() << "AutoTest.Run: Ignored plain output:" << output;
}
void TestOutputReader::reportCrash()
{
TestResultPtr result = createDefaultResult();
result->setDescription(tr("Test executable crashed."));
result->setResult(Result::MessageFatal);
m_futureInterface.reportResult(result);
}
void TestOutputReader::reportResult(const TestResultPtr &result)
{
m_futureInterface.reportResult(result);

View File

@@ -44,11 +44,14 @@ public:
virtual void processOutput(const QByteArray &outputLine) = 0;
virtual void processStdError(const QByteArray &output);
void reportCrash();
bool hadValidOutput() const { return m_hadValidOutput; }
signals:
void newOutputAvailable(const QByteArray &output);
protected:
virtual TestResultPtr createDefaultResult() const = 0;
void reportResult(const TestResultPtr &result);
QFutureInterface<TestResultPtr> m_futureInterface;
QProcess *m_testApplication; // not owned

View File

@@ -253,6 +253,7 @@ static void performTestRun(QFutureInterface<TestResultPtr> &futureInterface,
+ rcInfo(testConfiguration))));
}
if (testProcess.exitStatus() == QProcess::CrashExit) {
outputReader->reportCrash();
futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
TestRunner::tr("Test for project \"%1\" crashed.")
.arg(testConfiguration->displayName()) + processInformation(testProcess)

View File

@@ -42,6 +42,7 @@ static const char autoScrollKey[] = "AutoScrollResults";
static const char filterScanKey[] = "FilterScan";
static const char filtersKey[] = "WhiteListFilters";
static const char processArgsKey[] = "ProcessArgs";
static const char groupSuffix[] = ".group";
static const int defaultTimeout = 60000;
@@ -61,9 +62,11 @@ void TestSettings::toSettings(QSettings *s) const
s->setValue(processArgsKey, processArgs);
s->setValue(filterScanKey, filterScan);
s->setValue(filtersKey, whiteListFilters);
// store frameworks and their current active state
for (const Core::Id &id : frameworks.keys())
// store frameworks and their current active and grouping state
for (const Core::Id &id : frameworks.keys()) {
s->setValue(QLatin1String(id.name()), frameworks.value(id));
s->setValue(QLatin1String(id.name().append(groupSuffix)), frameworksGrouping.value(id));
}
s->endGroup();
}
@@ -82,9 +85,14 @@ void TestSettings::fromSettings(QSettings *s)
TestFrameworkManager *frameworkManager = TestFrameworkManager::instance();
const QList<Core::Id> &registered = frameworkManager->registeredFrameworkIds();
frameworks.clear();
frameworksGrouping.clear();
for (const Core::Id &id : registered) {
// get their active state
frameworks.insert(id, s->value(QLatin1String(id.name()),
frameworkManager->isActive(id)).toBool());
// and whether grouping is enabled
frameworksGrouping.insert(id, s->value(QLatin1String(id.name().append(groupSuffix)),
frameworkManager->groupingEnabled(id)).toBool());
}
s->endGroup();
}

View File

@@ -50,6 +50,7 @@ struct TestSettings
bool filterScan = false;
bool processArgs = false;
QHash<Core::Id, bool> frameworks;
QHash<Core::Id, bool> frameworksGrouping;
QStringList whiteListFilters;
};

View File

@@ -164,7 +164,7 @@ TestSettings TestSettingsWidget::settings() const
result.autoScroll = m_ui.autoScrollCB->isChecked();
result.processArgs = m_ui.processArgsCB->isChecked();
result.filterScan = m_ui.filterGroupBox->isChecked();
result.frameworks = frameworks();
frameworkSettings(result);
result.whiteListFilters = filters();
return result;
}
@@ -180,6 +180,11 @@ void TestSettingsWidget::populateFrameworksListWidget(const QHash<Core::Id, bool
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable);
item->setCheckState(0, frameworks.value(id) ? Qt::Checked : Qt::Unchecked);
item->setData(0, Qt::UserRole, id.toSetting());
item->setData(1, Qt::CheckStateRole, frameworkManager->groupingEnabled(id) ? Qt::Checked
: Qt::Unchecked);
item->setToolTip(0, tr("Enable or disable test frameworks to be handled by the AutoTest "
"plugin."));
item->setToolTip(1, tr("Enable or disable grouping of test cases by folder."));
}
}
@@ -189,18 +194,18 @@ void TestSettingsWidget::populateFiltersWidget(const QStringList &filters)
new QTreeWidgetItem(m_ui.filterTreeWidget, {filter} );
}
QHash<Core::Id, bool> TestSettingsWidget::frameworks() const
void TestSettingsWidget::frameworkSettings(TestSettings &settings) const
{
QHash<Core::Id, bool> frameworks;
const QAbstractItemModel *model = m_ui.frameworkTreeWidget->model();
QTC_ASSERT(model, return frameworks);
QTC_ASSERT(model, return);
const int itemCount = model->rowCount();
for (int row = 0; row < itemCount; ++row) {
const QModelIndex index = model->index(row, 0);
frameworks.insert(Core::Id::fromSetting(index.data(Qt::UserRole)),
index.data(Qt::CheckStateRole) == Qt::Checked);
QModelIndex idx = model->index(row, 0);
const Core::Id id = Core::Id::fromSetting(idx.data(Qt::UserRole));
settings.frameworks.insert(id, idx.data(Qt::CheckStateRole) == Qt::Checked);
idx = model->index(row, 1);
settings.frameworksGrouping.insert(id, idx.data(Qt::CheckStateRole) == Qt::Checked);
}
return frameworks;
}
QStringList TestSettingsWidget::filters() const
@@ -298,13 +303,20 @@ void TestSettingsPage::apply()
bool frameworkSyncNecessary = newSettings.frameworks != m_settings->frameworks;
bool forceReparse = newSettings.filterScan != m_settings->filterScan ||
newSettings.whiteListFilters.toSet() != m_settings->whiteListFilters.toSet();
const QList<Core::Id> changedIds = Utils::filtered(newSettings.frameworksGrouping.keys(),
[newSettings, this] (const Core::Id &id) {
return newSettings.frameworksGrouping[id] != m_settings->frameworksGrouping[id];
});
*m_settings = newSettings;
m_settings->toSettings(Core::ICore::settings());
TestFrameworkManager::instance()->activateFrameworksFromSettings(m_settings);
TestFrameworkManager *frameworkManager = TestFrameworkManager::instance();
frameworkManager->activateFrameworksFromSettings(m_settings);
if (frameworkSyncNecessary)
TestTreeModel::instance()->syncTestFrameworks();
else if (forceReparse)
TestTreeModel::instance()->parser()->emitUpdateTestTree();
else if (!changedIds.isEmpty())
TestTreeModel::instance()->rebuild(changedIds);
}
} // namespace Internal

View File

@@ -48,7 +48,7 @@ public:
private:
void populateFrameworksListWidget(const QHash<Core::Id, bool> &frameworks);
void populateFiltersWidget(const QStringList &filters);
QHash<Core::Id, bool> frameworks() const;
void frameworkSettings(TestSettings &settings) const;
QStringList filters() const;
void onFrameworkItemChanged();
void onAddFilterClicked();

View File

@@ -183,12 +183,29 @@ Warning: this is an experimental feature and might lead to failing to execute th
<bool>false</bool>
</property>
<property name="headerHidden">
<bool>true</bool>
<bool>false</bool>
</property>
<property name="columnCount">
<number>2</number>
</property>
<attribute name="headerDefaultSectionSize">
<number>150</number>
</attribute>
<column>
<property name="text">
<string>Framework</string>
</property>
<property name="toolTip">
<string>Selects the test frameworks to be handled by the AutoTest plugin.</string>
</property>
</column>
<column>
<property name="text">
<string>Group</string>
</property>
<property name="toolTip">
<string>Enables grouping of test cases.</string>
</property>
</column>
</widget>
</item>

View File

@@ -32,6 +32,7 @@
#include <cpptools/cppmodelmanager.h>
#include <cpptools/cpptoolsreuse.h>
#include <texteditor/texteditor.h>
#include <utils/utilsicons.h>
#include <QIcon>
@@ -43,21 +44,31 @@ TestTreeItem::TestTreeItem(const QString &name, const QString &filePath, Type ty
m_filePath(filePath),
m_type(type)
{
m_checked = (m_type == TestCase || m_type == TestFunctionOrSet || m_type == Root)
? Qt::Checked : Qt::Unchecked;
switch (m_type) {
case Root:
case GroupNode:
case TestCase:
case TestFunctionOrSet:
m_checked = Qt::Checked;
break;
default:
m_checked = Qt::Unchecked;
break;
}
}
static QIcon testTreeIcon(TestTreeItem::Type type)
{
static QIcon icons[] = {
QIcon(),
Utils::Icons::OPENFILE.icon(),
CPlusPlus::Icons::iconForType(CPlusPlus::Icons::ClassIconType),
CPlusPlus::Icons::iconForType(CPlusPlus::Icons::SlotPrivateIconType),
QIcon(":/images/data.png")
};
if (int(type) >= int(sizeof icons / sizeof *icons))
return icons[2];
return icons[3];
return icons[type];
}
@@ -76,6 +87,8 @@ QVariant TestTreeItem::data(int /*column*/, int role) const
case Qt::CheckStateRole:
return QVariant();
case LinkRole: {
if (m_type == GroupNode)
return QVariant();
QVariant itemLink;
itemLink.setValue(Utils::Link(m_filePath, m_line, m_column));
return itemLink;
@@ -105,6 +118,7 @@ Qt::ItemFlags TestTreeItem::flags(int /*column*/) const
static const Qt::ItemFlags defaultFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
switch (m_type) {
case Root:
case GroupNode:
return Qt::ItemIsEnabled | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable;
case TestCase:
return defaultFlags | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable;
@@ -164,6 +178,7 @@ void TestTreeItem::setChecked(const Qt::CheckState checkState)
break;
}
case Root:
case GroupNode:
case TestFunctionOrSet:
case TestCase: {
Qt::CheckState usedState = (checkState == Qt::Unchecked ? Qt::Unchecked : Qt::Checked);
@@ -185,6 +200,7 @@ Qt::CheckState TestTreeItem::checked() const
{
switch (m_type) {
case Root:
case GroupNode:
case TestCase:
case TestFunctionOrSet:
case TestDataTag:
@@ -268,6 +284,9 @@ bool TestTreeItem::lessThan(const TestTreeItem *other, SortMode mode) const
return index().row() > other->index().row();
return lhs > rhs;
case Naturally: {
if (m_type == GroupNode && other->type() == GroupNode)
return m_filePath > other->filePath();
const Utils::Link &leftLink = data(0, LinkRole).value<Utils::Link>();
const Utils::Link &rightLink = other->data(0, LinkRole).value<Utils::Link>();
if (leftLink.targetFileName == rightLink.targetFileName) {
@@ -282,6 +301,16 @@ bool TestTreeItem::lessThan(const TestTreeItem *other, SortMode mode) const
}
}
bool TestTreeItem::isGroupNodeFor(const TestTreeItem *other) const
{
QTC_ASSERT(other, return false);
if (type() != TestTreeItem::GroupNode)
return false;
// for now there's only the possibility to have 'Folder' nodes
return QFileInfo(other->filePath()).absolutePath() == filePath();
}
QSet<QString> TestTreeItem::internalTargets() const
{
auto cppMM = CppTools::CppModelManager::instance();
@@ -301,7 +330,7 @@ QSet<QString> TestTreeItem::internalTargets() const
void TestTreeItem::revalidateCheckState()
{
const Type ttiType = type();
if (ttiType != TestCase && ttiType != TestFunctionOrSet && ttiType != Root)
if (ttiType != TestCase && ttiType != TestFunctionOrSet && ttiType != Root && ttiType != GroupNode)
return;
if (childCount() == 0) // can this happen? (we're calling revalidateCS() on parentItem()
return;
@@ -323,13 +352,13 @@ void TestTreeItem::revalidateCheckState()
foundPartiallyChecked |= (child->checked() == Qt::PartiallyChecked);
if (foundPartiallyChecked || (foundChecked && foundUnchecked)) {
m_checked = Qt::PartiallyChecked;
if (ttiType == TestFunctionOrSet || ttiType == TestCase)
if (ttiType == TestFunctionOrSet || ttiType == TestCase || ttiType == GroupNode)
parentItem()->revalidateCheckState();
return;
}
}
m_checked = (foundUnchecked ? Qt::Unchecked : Qt::Checked);
if (ttiType == TestFunctionOrSet || ttiType == TestCase)
if (ttiType == TestFunctionOrSet || ttiType == TestCase || ttiType == GroupNode)
parentItem()->revalidateCheckState();
}

View File

@@ -55,6 +55,7 @@ public:
enum Type
{
Root,
GroupNode,
TestCase,
TestFunctionOrSet,
TestDataTag,
@@ -112,7 +113,8 @@ public:
virtual bool lessThan(const TestTreeItem *other, SortMode mode) const;
virtual TestTreeItem *find(const TestParseResult *result) = 0;
virtual bool modify(const TestParseResult *result) = 0;
virtual bool isGroupNodeFor(const TestTreeItem *other) const;
virtual TestTreeItem *createParentGroupNode() const = 0;
virtual QSet<QString> internalTargets() const;
protected:
typedef std::function<bool(const TestTreeItem *)> CompareFunction;

View File

@@ -73,12 +73,11 @@ TestTreeModel::~TestTreeModel()
void TestTreeModel::setupParsingConnections()
{
if (!m_connectionsInitialized)
m_parser->setDirty();
m_parser->setState(TestCodeParser::Idle);
if (m_connectionsInitialized)
static bool connectionsInitialized = false;
if (connectionsInitialized)
return;
m_parser->setDirty();
m_parser->setState(TestCodeParser::Idle);
ProjectExplorer::SessionManager *sm = ProjectExplorer::SessionManager::instance();
connect(sm, &ProjectExplorer::SessionManager::startupProjectChanged,
@@ -97,7 +96,7 @@ void TestTreeModel::setupParsingConnections()
m_parser, &TestCodeParser::onQmlDocumentUpdated, Qt::QueuedConnection);
connect(qmlJsMM, &QmlJS::ModelManagerInterface::aboutToRemoveFiles,
this, &TestTreeModel::removeFiles, Qt::QueuedConnection);
m_connectionsInitialized = true;
connectionsInitialized = true;
}
bool TestTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
@@ -111,6 +110,7 @@ bool TestTreeModel::setData(const QModelIndex &index, const QVariant &value, int
if (role == Qt::CheckStateRole) {
switch (item->type()) {
case TestTreeItem::Root:
case TestTreeItem::GroupNode:
case TestTreeItem::TestCase:
if (item->childCount() > 0)
emit dataChanged(index.child(0, 0), index.child(item->childCount() - 1, 0));
@@ -175,6 +175,31 @@ void TestTreeModel::syncTestFrameworks()
emit updatedActiveFrameworks(sortedIds.size());
}
void TestTreeModel::rebuild(const QList<Core::Id> &frameworkIds)
{
TestFrameworkManager *frameworkManager = TestFrameworkManager::instance();
for (const Core::Id &id : frameworkIds) {
TestTreeItem *frameworkRoot = frameworkManager->rootNodeForTestFramework(id);
const bool groupingEnabled = TestFrameworkManager::instance()->groupingEnabled(id);
for (int row = frameworkRoot->childCount() - 1; row >= 0; --row) {
auto testItem = frameworkRoot->childItem(row);
if (!groupingEnabled && testItem->type() == TestTreeItem::GroupNode) {
// do not re-insert the GroupNode, but process its children and delete it afterwards
for (int childRow = testItem->childCount() - 1; childRow >= 0; --childRow) {
// FIXME should this be done recursively until we have a non-GroupNode?
TestTreeItem *childTestItem = testItem->childItem(childRow);
takeItem(childTestItem);
insertItemInParent(childTestItem, frameworkRoot, groupingEnabled);
}
delete takeItem(testItem);
} else {
takeItem(testItem);
insertItemInParent(testItem, frameworkRoot, groupingEnabled);
}
}
}
}
void TestTreeModel::removeFiles(const QStringList &files)
{
for (const QString &file : files)
@@ -240,6 +265,24 @@ bool TestTreeModel::sweepChildren(TestTreeItem *item)
return hasChanged;
}
void TestTreeModel::insertItemInParent(TestTreeItem *item, TestTreeItem *root, bool groupingEnabled)
{
TestTreeItem *parentNode = root;
if (groupingEnabled) {
parentNode = root->findChildBy([item] (const TestTreeItem *it) {
return it->isGroupNodeFor(item);
});
if (!parentNode) {
parentNode = item->createParentGroupNode();
if (!parentNode) // we might not get a group node at all
parentNode = root;
else
root->appendChild(parentNode);
}
}
parentNode->appendChild(item);
}
void TestTreeModel::onParseResultReady(const TestParseResultPtr result)
{
TestTreeItem *rootNode
@@ -250,10 +293,19 @@ void TestTreeModel::onParseResultReady(const TestParseResultPtr result)
void TestTreeModel::handleParseResult(const TestParseResult *result, TestTreeItem *parentNode)
{
const bool groupingEnabled =
TestFrameworkManager::instance()->groupingEnabled(result->frameworkId);
// lookup existing items
if (TestTreeItem *toBeModified = parentNode->find(result)) {
// found existing item... Do not remove
toBeModified->markForRemoval(false);
// if it's a reparse we need to mark the group node as well to avoid purging it in sweep()
if (groupingEnabled) {
if (auto directParent = toBeModified->parentItem()) {
if (directParent->type() == TestTreeItem::GroupNode)
directParent->markForRemoval(false);
}
}
// modify and when content has changed inform ui
if (toBeModified->modify(result)) {
const QModelIndex &idx = indexForItem(toBeModified);
@@ -267,7 +319,8 @@ void TestTreeModel::handleParseResult(const TestParseResult *result, TestTreeIte
// if there's no matching item, add the new one
TestTreeItem *newItem = result->createTestTreeItem();
QTC_ASSERT(newItem, return);
parentNode->appendChild(newItem);
insertItemInParent(newItem, parentNode, groupingEnabled);
// new items are checked by default - revalidation of parents might be necessary
if (parentNode->checked() != Qt::Checked) {
parentNode->revalidateCheckState();

View File

@@ -56,6 +56,7 @@ public:
QList<TestConfiguration *> getSelectedTests() const;
void syncTestFrameworks();
void rebuild(const QList<Core::Id> &frameworkIds);
#ifdef WITH_TESTS
int autoTestsCount() const;
@@ -86,12 +87,12 @@ private:
void removeTestRootNodes();
void removeFiles(const QStringList &files);
bool sweepChildren(TestTreeItem *item);
static void insertItemInParent(TestTreeItem *item, TestTreeItem *root, bool groupingEnabled);
explicit TestTreeModel(QObject *parent = 0);
void setupParsingConnections();
TestCodeParser *m_parser;
bool m_connectionsInitialized = false;
};
class TestTreeSortFilterModel : public QSortFilterProxyModel

View File

@@ -274,13 +274,20 @@ void CdbEngine::init()
// Create local list of mappings in native separators
m_sourcePathMappings.clear();
const QString &packageSources = runParameters().qtPackageSourceLocation;
if (!packageSources.isEmpty()) {
for (const QString &buildPath : qtBuildPaths()) {
m_sourcePathMappings.push_back({QDir::toNativeSeparators(buildPath),
QDir::toNativeSeparators(packageSources)});
}
}
const QSharedPointer<GlobalDebuggerOptions> globalOptions = Internal::globalDebuggerOptions();
SourcePathMap sourcePathMap = globalOptions->sourcePathMap;
if (!sourcePathMap.isEmpty()) {
m_sourcePathMappings.reserve(sourcePathMap.size());
for (auto it = sourcePathMap.constBegin(), cend = sourcePathMap.constEnd(); it != cend; ++it) {
m_sourcePathMappings.push_back(SourcePathMapping(QDir::toNativeSeparators(it.key()),
QDir::toNativeSeparators(it.value())));
m_sourcePathMappings.push_back({QDir::toNativeSeparators(it.key()),
QDir::toNativeSeparators(it.value())});
}
}
// update source path maps from debugger start params

View File

@@ -121,5 +121,8 @@ QAction *addAction(QMenu *menu, const QString &d1, const QString &d2, bool on,
QAction *addCheckableAction(QMenu *menu, const QString &display, bool on, bool checked,
const std::function<void()> &onTriggered);
// Qt's various build paths for unpatched versions
QStringList qtBuildPaths();
} // namespace Internal
} // namespace Debugger

View File

@@ -139,6 +139,7 @@ public:
QString startMessage; // First status message shown.
QString debugInfoLocation; // Gdb "set-debug-file-directory".
QStringList debugSourceLocation; // Gdb "directory"
QString qtPackageSourceLocation;
bool isSnapshot = false; // Set if created internally.
ProjectExplorer::Abi toolChainAbi;

View File

@@ -830,6 +830,9 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, Kit *kit, bool allowTer
m_runParameters.macroExpander = kit->macroExpander();
m_runParameters.debugger = DebuggerKitInformation::runnable(kit);
if (QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(kit))
m_runParameters.qtPackageSourceLocation = qtVersion->qtPackageSourcePath().toString();
if (auto aspect = runConfig ? runConfig->extraAspect<DebuggerRunConfigurationAspect>() : nullptr) {
m_runParameters.isCppDebugging = aspect->useCppDebugger();
m_runParameters.isQmlDebugging = aspect->useQmlDebugger();

View File

@@ -33,6 +33,7 @@
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
#include <utils/synchronousprocess.h>
#include <utils/hostosinfo.h>
#include <QStandardItemModel>
#include <QTreeView>
@@ -44,20 +45,6 @@
using namespace Utils;
// Qt's various build paths for unpatched versions.
#if defined(Q_OS_WIN)
static const char* qtBuildPaths[] = {
"Q:/qt5_workdir/w/s",
"C:/work/build/qt5_workdir/w/s",
"c:/users/qt/work/qt",
"c:/Users/qt/work/install"
};
#elif defined(Q_OS_MAC)
static const char* qtBuildPaths[] = {};
#else
static const char* qtBuildPaths[] = {"/var/tmp/qt-src"};
#endif
enum { SourceColumn, TargetColumn, ColumnCount };
namespace Debugger {
@@ -66,6 +53,19 @@ namespace Internal {
typedef QPair<QString, QString> Mapping;
typedef DebuggerSourcePathMappingWidget::SourcePathMap SourcePathMap;
// Qt's various build paths for unpatched versions.
QStringList qtBuildPaths()
{
if (HostOsInfo::isWindowsHost()) {
return {"Q:/qt5_workdir/w/s",
"C:/work/build/qt5_workdir/w/s",
"c:/users/qt/work/qt",
"c:/Users/qt/work/install"};
} else {
return {};
}
}
/*!
\class Debugger::Internal::SourcePathMappingModel
@@ -232,7 +232,7 @@ DebuggerSourcePathMappingWidget::DebuggerSourcePathMappingWidget(QWidget *parent
auto buttonLayout = new QVBoxLayout;
buttonLayout->addWidget(m_addButton);
buttonLayout->addWidget(m_addQtButton);
m_addQtButton->setVisible(sizeof(qtBuildPaths) > 0);
m_addQtButton->setVisible(!qtBuildPaths().isEmpty());
m_addQtButton->setToolTip(tr("<p>Add a mapping for Qt's source folders "
"when using an unpatched version of Qt."));
buttonLayout->addWidget(m_removeButton);
@@ -364,13 +364,11 @@ void DebuggerSourcePathMappingWidget::slotAdd()
void DebuggerSourcePathMappingWidget::slotAddQt()
{
// Add a mapping for various Qt build locations in case of unpatched builds.
const QString qtSourcesPath =
QFileDialog::getExistingDirectory(this, tr("Qt Sources"));
const QString qtSourcesPath = QFileDialog::getExistingDirectory(this, tr("Qt Sources"));
if (qtSourcesPath.isEmpty())
return;
const size_t buildPathCount = sizeof(qtBuildPaths)/sizeof(qtBuildPaths[0]);
for (size_t i = 0; i != buildPathCount; ++i) // use != to avoid 0<0 which triggers warning on Mac
m_model->addMapping(QString::fromLatin1(qtBuildPaths[i]), qtSourcesPath);
for (const QString &buildPath : qtBuildPaths())
m_model->addMapping(buildPath, qtSourcesPath);
resizeColumns();
setCurrentRow(m_model->rowCount() - 1);
}
@@ -446,13 +444,11 @@ DebuggerSourcePathMappingWidget::SourcePathMap
// The profile could also get a function to extract the required information from
// its information to avoid this dependency (as we do for the environment).
const QString qtInstallPath = findQtInstallPath(qmake);
SourcePathMap rc = in;
const size_t buildPathCount = sizeof(qtBuildPaths)/sizeof(const char *);
if (qtInstallPath.isEmpty() || buildPathCount == 0)
return rc;
if (qtInstallPath.isEmpty())
return in;
for (size_t i = 0; i != buildPathCount; ++i) { // use != to avoid 0<0 which triggers warning on Mac
const QString buildPath = QString::fromLatin1(qtBuildPaths[i]);
SourcePathMap rc = in;
for (const QString &buildPath : qtBuildPaths()) {
if (!rc.contains(buildPath)) // Do not overwrite user settings.
rc.insert(buildPath, qtInstallPath);
}

View File

@@ -267,7 +267,7 @@ QVariantMap IosRunConfiguration::toMap() const
QString IosRunConfiguration::buildSystemTarget() const
{
return static_cast<QmakeProject *>(target()->project())->mapProFilePathToTarget(m_profilePath);
return m_profilePath.toString();
}
QString IosRunConfiguration::disabledReason() const

View File

@@ -153,11 +153,6 @@ DeployConfigurationFactory::~DeployConfigurationFactory()
g_deployConfigurationFactories.removeOne(this);
}
QList<DeployConfigurationFactory *> DeployConfigurationFactory::allDeployConfigurationFactories()
{
return g_deployConfigurationFactories;
}
QList<Core::Id> DeployConfigurationFactory::availableCreationIds(Target *parent) const
{
if (!canHandle(parent))

View File

@@ -80,8 +80,6 @@ public:
DeployConfigurationFactory();
~DeployConfigurationFactory();
static QList<DeployConfigurationFactory *> allDeployConfigurationFactories();
// used to show the list of possible additons to a target, returns a list of types
QList<Core::Id> availableCreationIds(Target *parent) const;
// used to translate the types to names to display to the user

View File

@@ -128,11 +128,6 @@ Core::Id ProjectExplorer::idFromMap(const QVariantMap &map)
return Core::Id::fromSetting(map.value(QLatin1String(CONFIGURATION_ID_KEY)));
}
QString ProjectExplorer::displayNameFromMap(const QVariantMap &map)
{
return map.value(QLatin1String(DISPLAY_NAME_KEY), QString()).toString();
}
bool StatefulProjectConfiguration::isEnabled() const
{
return m_isEnabled;

View File

@@ -112,8 +112,7 @@ private:
bool m_isEnabled = false;
};
// helper functions:
// helper function:
PROJECTEXPLORER_EXPORT Core::Id idFromMap(const QVariantMap &map);
PROJECTEXPLORER_EXPORT QString displayNameFromMap(const QVariantMap &map);
} // namespace ProjectExplorer

View File

@@ -2036,8 +2036,6 @@ void ProjectExplorerPluginPrivate::executeRunConfiguration(RunConfiguration *run
return;
}
emit m_instance->aboutToExecuteProject(runConfiguration->target()->project(), runMode);
startRunControl(runControl);
}

View File

@@ -170,7 +170,6 @@ signals:
// or the file list of a specific project has changed.
void fileListChanged();
void aboutToExecuteProject(ProjectExplorer::Project *project, Core::Id runMode);
void recentProjectsChanged();
void settingsChanged();
@@ -234,10 +233,10 @@ private slots:
void testToolChainManager_data();
void testToolChainManager();
void testUserFileAccessor_prepareSettings();
void testUserFileAccessor_prepareSettingsObsoleteVersion();
void testUserFileAccessor_prepareSettingsObsoleteVersionNewVersion();
void testUserFileAccessor_prepareToSaveSettings();
void testUserFileAccessor_prepareToReadSettings();
void testUserFileAccessor_prepareToReadSettingsObsoleteVersion();
void testUserFileAccessor_prepareToReadSettingsObsoleteVersionNewVersion();
void testUserFileAccessor_prepareToWriteSettings();
void testUserFileAccessor_mergeSettings();
void testUserFileAccessor_mergeSettingsEmptyUser();
void testUserFileAccessor_mergeSettingsEmptyShared();

View File

@@ -262,9 +262,6 @@ void Target::addDeployConfiguration(DeployConfiguration *dc)
QTC_ASSERT(dc && !d->m_deployConfigurations.contains(dc), return);
Q_ASSERT(dc->target() == this);
if (DeployConfigurationFactory::allDeployConfigurationFactories().isEmpty())
return;
// Check that we don't have a configuration with the same displayName
QString configurationDisplayName = dc->displayName();
QStringList displayNames = Utils::transform(d->m_deployConfigurations, &DeployConfiguration::displayName);

Some files were not shown because too many files have changed in this diff Show More