forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/4.7'
Change-Id: I00dd929a4ed32af8f1b76cea57a7c49239dafc7c
This commit is contained in:
19
README.md
19
README.md
@@ -22,7 +22,7 @@ Prerequisites:
|
||||
* jom
|
||||
* On Mac OS X: latest Xcode
|
||||
* On Linux: g++ 4.9 or later
|
||||
* LLVM/Clang 5.0.0 or later (optional, needed for the Clang Code Model, see the
|
||||
* LLVM/Clang 6.0.0 or later (optional, needed for the Clang Code Model, see the
|
||||
section "Get LLVM/Clang for the Clang Code Model")
|
||||
* CMake (only for manual builds of LLVM/Clang)
|
||||
* Qbs 1.7.x (optional, sources also contain Qbs itself)
|
||||
@@ -206,7 +206,7 @@ or using shadow builds.
|
||||
## Get LLVM/Clang for the Clang Code Model
|
||||
|
||||
The Clang Code Model depends on the LLVM/Clang libraries. The currently
|
||||
supported LLVM/Clang version is 5.0.
|
||||
supported LLVM/Clang version is 6.0.
|
||||
|
||||
### Prebuilt LLVM/Clang packages
|
||||
|
||||
@@ -233,9 +233,9 @@ GCC 4 binaries. On Ubuntu, you can download the package from
|
||||
http://apt.llvm.org/ with:
|
||||
|
||||
wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/`lsb_release -cs`/ llvm-toolchain-`lsb_release -cs`-5.0 main"
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/`lsb_release -cs`/ llvm-toolchain-`lsb_release -cs`-6.0 main"
|
||||
sudo apt-get update
|
||||
sudo apt-get install llvm-5.0 libclang-5.0-dev
|
||||
sudo apt-get install llvm-6.0 libclang-6.0-dev
|
||||
|
||||
There is a workaround to set _GLIBCXX_USE_CXX11_ABI to 1 or 0, but we recommend
|
||||
to download the package from http://apt.llvm.org/.
|
||||
@@ -251,11 +251,11 @@ http://llvm.org/docs/GettingStarted.html#git-mirror:
|
||||
|
||||
1. Clone LLVM and checkout a suitable branch
|
||||
|
||||
git clone -b release_50 https://git.llvm.org/git/llvm
|
||||
git clone -b release_60-based https://code.qt.io/clang/llvm
|
||||
|
||||
2. Clone Clang into llvm/tools/clang and checkout a suitable branch
|
||||
|
||||
git clone -b release_50 https://git.llvm.org/git/clang llvm/tools/clang
|
||||
git clone -b release_60-based https://code.qt.io/clang/clang llvm/tools/clang
|
||||
|
||||
3. Build and install LLVM/Clang
|
||||
|
||||
@@ -285,7 +285,8 @@ we thank the authors who made this possible:
|
||||
|
||||
Distributed under GNU LIBRARY GENERAL PUBLIC LICENSE Version 2 (LGPL2).
|
||||
|
||||
Integrated with patches from QtCreator/dist/clang/patches, see README.md there.
|
||||
Integrated with patches from
|
||||
http://code.qt.io/cgit/clang/clang-tools-extra.git/.
|
||||
|
||||
### LLVM/Clang
|
||||
|
||||
@@ -298,7 +299,9 @@ we thank the authors who made this possible:
|
||||
Distributed under the University of Illinois/NCSA Open Source License (NCSA),
|
||||
see https://github.com/llvm-mirror/llvm/blob/master/LICENSE.TXT
|
||||
|
||||
With additional patches from QtCreator/dist/clang/patches, see README.md there.
|
||||
With backported/additional patches from
|
||||
http://code.qt.io/cgit/clang/llvm.git/
|
||||
http://code.qt.io/cgit/clang/clang.git/
|
||||
|
||||
### Reference implementation for std::experimental::optional
|
||||
|
||||
|
@@ -1,71 +0,0 @@
|
||||
diff --git a/tools/clang/lib/Frontend/ASTUnit.cpp b/tools/clang/lib/Frontend/ASTUnit.cpp
|
||||
index 1094e6d089..5a4cddbebe 100644
|
||||
--- a/tools/clang/lib/Frontend/ASTUnit.cpp
|
||||
+++ b/tools/clang/lib/Frontend/ASTUnit.cpp
|
||||
@@ -243,7 +243,8 @@ static unsigned getDeclShowContexts(const NamedDecl *ND,
|
||||
|
||||
uint64_t Contexts = 0;
|
||||
if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND) ||
|
||||
- isa<ClassTemplateDecl>(ND) || isa<TemplateTemplateParmDecl>(ND)) {
|
||||
+ isa<ClassTemplateDecl>(ND) || isa<TemplateTemplateParmDecl>(ND) ||
|
||||
+ isa<TypeAliasTemplateDecl>(ND)) {
|
||||
// Types can appear in these contexts.
|
||||
if (LangOpts.CPlusPlus || !isa<TagDecl>(ND))
|
||||
Contexts |= (1LL << CodeCompletionContext::CCC_TopLevel)
|
||||
diff --git a/tools/clang/lib/Parse/ParseTemplate.cpp b/tools/clang/lib/Parse/ParseTemplate.cpp
|
||||
index 944cd775d5..6aba10e5c7 100644
|
||||
--- a/tools/clang/lib/Parse/ParseTemplate.cpp
|
||||
+++ b/tools/clang/lib/Parse/ParseTemplate.cpp
|
||||
@@ -198,9 +198,11 @@ Parser::ParseSingleDeclarationAfterTemplate(
|
||||
|
||||
if (Tok.is(tok::kw_using)) {
|
||||
// FIXME: We should return the DeclGroup to the caller.
|
||||
- ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
|
||||
- prefixAttrs);
|
||||
- return nullptr;
|
||||
+ auto usingDeclPtr = ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
|
||||
+ prefixAttrs);
|
||||
+ if (!usingDeclPtr || !usingDeclPtr.get().isSingleDecl())
|
||||
+ return nullptr;
|
||||
+ return usingDeclPtr.get().getSingleDecl();
|
||||
}
|
||||
|
||||
// Parse the declaration specifiers, stealing any diagnostics from
|
||||
@@ -1023,8 +1025,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
|
||||
? OO_None
|
||||
: TemplateName.OperatorFunctionId.Operator;
|
||||
|
||||
- TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
|
||||
- SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
|
||||
+ TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
|
||||
+ SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
|
||||
LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
|
||||
|
||||
Tok.setAnnotationValue(TemplateId);
|
||||
diff --git a/tools/clang/test/Index/code-completion.cpp b/tools/clang/test/Index/code-completion.cpp
|
||||
index f52bb10a35..00f158f3d0 100644
|
||||
--- a/tools/clang/test/Index/code-completion.cpp
|
||||
+++ b/tools/clang/test/Index/code-completion.cpp
|
||||
@@ -37,6 +37,16 @@ Z::operator int() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
+template <typename T>
|
||||
+struct Foo { T member; };
|
||||
+
|
||||
+template<typename T> using Bar = Foo<T>;
|
||||
+
|
||||
+void test_template_alias() {
|
||||
+ // RUN: env CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:47:1 %s | FileCheck -check-prefix=CHECK-TEMPLATE-ALIAS %s
|
||||
+
|
||||
+}
|
||||
+
|
||||
// CHECK-MEMBER: FieldDecl:{ResultType double}{TypedText member}
|
||||
// CHECK-MEMBER: FieldDecl:{ResultType int}{Text X::}{TypedText member}
|
||||
// CHECK-MEMBER: FieldDecl:{ResultType float}{Text Y::}{TypedText member}
|
||||
@@ -88,3 +98,5 @@ Z::operator int() const {
|
||||
// CHECK-EXPR-NEXT: Class name
|
||||
// CHECK-EXPR-NEXT: Nested name specifier
|
||||
// CHECK-EXPR-NEXT: Objective-C interface
|
||||
+
|
||||
+// CHECK-TEMPLATE-ALIAS: AliasTemplateDecl:{TypedText Bar}{LeftAngle <}{Placeholder typename T}{RightAngle >} (50)
|
@@ -1,50 +0,0 @@
|
||||
diff --git a/tools/clang/lib/Sema/SemaCodeComplete.cpp b/tools/clang/lib/Sema/SemaCodeComplete.cpp
|
||||
index 4de7d42207..7001849426 100644
|
||||
--- a/tools/clang/lib/Sema/SemaCodeComplete.cpp
|
||||
+++ b/tools/clang/lib/Sema/SemaCodeComplete.cpp
|
||||
@@ -4286,9 +4286,12 @@ static void mergeCandidatesWithResults(Sema &SemaRef,
|
||||
});
|
||||
|
||||
// Add the remaining viable overload candidates as code-completion results.
|
||||
- for (auto &Candidate : CandidateSet)
|
||||
+ for (auto &Candidate : CandidateSet) {
|
||||
+ if (Candidate.Function && Candidate.Function->isDeleted())
|
||||
+ continue;
|
||||
if (Candidate.Viable)
|
||||
Results.push_back(ResultCandidate(Candidate.Function));
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/tools/clang/test/Index/complete-constructor-params.cpp b/tools/clang/test/Index/complete-constructor-params.cpp
|
||||
index 6685626a58..949077a214 100644
|
||||
--- a/tools/clang/test/Index/complete-constructor-params.cpp
|
||||
+++ b/tools/clang/test/Index/complete-constructor-params.cpp
|
||||
@@ -18,6 +18,20 @@ int main() {
|
||||
int(42);
|
||||
}
|
||||
|
||||
+struct Foo {
|
||||
+ Foo() = default;
|
||||
+ Foo(const Foo&) = delete;
|
||||
+};
|
||||
+
|
||||
+struct Bar {
|
||||
+ Foo f;
|
||||
+};
|
||||
+
|
||||
+void function() {
|
||||
+ Bar b1;
|
||||
+ Bar b2(b1);
|
||||
+}
|
||||
+
|
||||
// RUN: c-index-test -code-completion-at=%s:11:10 %s | FileCheck -check-prefix=CHECK-CC1 %s
|
||||
// CHECK-CC1: OverloadCandidate:{Text S}{LeftParen (}{CurrentParameter const S<int> &}{RightParen )} (1)
|
||||
// CHECK-CC1: OverloadCandidate:{Text S}{LeftParen (}{CurrentParameter int}{Comma , }{Placeholder U}{Comma , }{Placeholder U}{RightParen )} (1)
|
||||
@@ -138,3 +152,6 @@ int main() {
|
||||
// CHECK-CC10-NEXT: Class name
|
||||
// CHECK-CC10-NEXT: Nested name specifier
|
||||
// CHECK-CC10-NEXT: Objective-C interface
|
||||
+
|
||||
+// RUN: c-index-test -code-completion-at=%s:32:12 -std=c++11 %s | FileCheck -check-prefix=CHECK-CC11 %s
|
||||
+// CHECK-CC11-NOT: OverloadCandidate:{Text Bar}{LeftParen (}{CurrentParameter const Bar &}{RightParen )} (1)
|
@@ -1,34 +0,0 @@
|
||||
--- /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;
|
@@ -1,266 +0,0 @@
|
||||
--- 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) {
|
@@ -1,33 +0,0 @@
|
||||
--- 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;
|
||||
}
|
||||
|
@@ -1,154 +0,0 @@
|
||||
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
|
@@ -1,79 +0,0 @@
|
||||
--- 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?
|
||||
}
|
||||
|
@@ -1,78 +0,0 @@
|
||||
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
|
@@ -1,47 +0,0 @@
|
||||
--- 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
|
@@ -1,117 +0,0 @@
|
||||
--- 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
|
||||
+}
|
||||
+}
|
@@ -1,37 +0,0 @@
|
||||
--- 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
|
@@ -1,47 +0,0 @@
|
||||
--- 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
|
@@ -1,25 +0,0 @@
|
||||
diff --git a/tools/clang/tools/libclang/CIndex.cpp b/tools/clang/tools/libclang/CIndex.cpp
|
||||
index 66b6edc8b1..281ab77c23 100644
|
||||
--- a/tools/clang/tools/libclang/CIndex.cpp
|
||||
+++ b/tools/clang/tools/libclang/CIndex.cpp
|
||||
@@ -8479,4 +8479,8 @@ static int LLVM_ATTRIBUTE_UNUSED ClangTidyPluginAnchorDestination =
|
||||
extern volatile int ClangIncludeFixerPluginAnchorSource;
|
||||
static int LLVM_ATTRIBUTE_UNUSED ClangIncludeFixerPluginAnchorDestination =
|
||||
ClangIncludeFixerPluginAnchorSource;
|
||||
+
|
||||
+// This anchor is used to force the linker to link the clazy plugin.
|
||||
+extern volatile int ClazyPluginAnchorSource;
|
||||
+static int LLVM_ATTRIBUTE_UNUSED ClazyPluginAnchorDestination = ClazyPluginAnchorSource;
|
||||
#endif
|
||||
diff --git a/tools/clang/tools/libclang/CMakeLists.txt b/tools/clang/tools/libclang/CMakeLists.txt
|
||||
index 4440637820..6798d2ee8b 100644
|
||||
--- a/tools/clang/tools/libclang/CMakeLists.txt
|
||||
+++ b/tools/clang/tools/libclang/CMakeLists.txt
|
||||
@@ -51,6 +51,7 @@ if (TARGET clangTidyPlugin)
|
||||
add_definitions(-DCLANG_TOOL_EXTRA_BUILD)
|
||||
list(APPEND LIBS clangTidyPlugin)
|
||||
list(APPEND LIBS clangIncludeFixerPlugin)
|
||||
+ list(APPEND LIBS clazyPlugin)
|
||||
endif ()
|
||||
|
||||
find_library(DL_LIBRARY_PATH dl)
|
@@ -1,13 +0,0 @@
|
||||
diff --git a/tools/clang/tools/extra/CMakeLists.txt b/tools/clang/tools/extra/CMakeLists.txt
|
||||
index 760340a6..53f720c4 100644
|
||||
--- a/tools/clang/tools/extra/CMakeLists.txt
|
||||
+++ b/tools/clang/tools/extra/CMakeLists.txt
|
||||
@@ -5,6 +5,8 @@ if(CLANG_ENABLE_STATIC_ANALYZER)
|
||||
add_subdirectory(clang-tidy)
|
||||
add_subdirectory(clang-tidy-vs)
|
||||
endif()
|
||||
+set(CLAZY_BUILD_WITH_CLANG 1)
|
||||
+add_subdirectory(clazy)
|
||||
|
||||
add_subdirectory(change-namespace)
|
||||
add_subdirectory(clang-query)
|
@@ -1,23 +0,0 @@
|
||||
diff --git a/lib/Transforms/CMakeLists.txt b/lib/Transforms/CMakeLists.txt
|
||||
index 67bdeb27212..7fcddb15904 100644
|
||||
--- a/lib/Transforms/CMakeLists.txt
|
||||
+++ b/lib/Transforms/CMakeLists.txt
|
||||
@@ -4,6 +4,5 @@ add_subdirectory(InstCombine)
|
||||
add_subdirectory(Scalar)
|
||||
add_subdirectory(IPO)
|
||||
add_subdirectory(Vectorize)
|
||||
-add_subdirectory(Hello)
|
||||
add_subdirectory(ObjCARC)
|
||||
add_subdirectory(Coroutines)
|
||||
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
|
||||
index 6cf5103bf44..0b9608a2e52 100644
|
||||
--- a/test/CMakeLists.txt
|
||||
+++ b/test/CMakeLists.txt
|
||||
@@ -35,7 +35,6 @@ endif()
|
||||
set(LLVM_TEST_DEPENDS
|
||||
BugpointPasses
|
||||
FileCheck
|
||||
- LLVMHello
|
||||
UnitTests
|
||||
bugpoint
|
||||
count
|
@@ -1,16 +0,0 @@
|
||||
diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp
|
||||
index 85e782b2c04..95f10753d96 100644
|
||||
--- a/lib/Support/MemoryBuffer.cpp
|
||||
+++ b/lib/Support/MemoryBuffer.cpp
|
||||
@@ -284,6 +284,11 @@ static bool shouldUseMmap(int FD,
|
||||
bool RequiresNullTerminator,
|
||||
int PageSize,
|
||||
bool IsVolatile) {
|
||||
+#ifdef _WIN32
|
||||
+ // Do not use mmap on Windows in order to avoid file locking
|
||||
+ return false;
|
||||
+#endif
|
||||
+
|
||||
// mmap may leave the buffer without null terminator if the file size changed
|
||||
// by the time the last page is mapped in, so avoid it if the file size is
|
||||
// likely to change.
|
@@ -1,144 +0,0 @@
|
||||
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
|
||||
|
@@ -1,546 +0,0 @@
|
||||
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..342fbd5279 100644
|
||||
--- a/tools/clang/unittests/libclang/LibclangTest.cpp
|
||||
+++ b/tools/clang/unittests/libclang/LibclangTest.cpp
|
||||
@@ -572,3 +572,35 @@ 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);
|
||||
+ if (Property == CXPrintingPolicy_ConstantsAsWritten || Property == CXPrintingPolicy_SuppressImplicitBase)
|
||||
+ continue; // These are not yet in clang 5.0.
|
||||
+
|
||||
+ clang_PrintingPolicy_setProperty(Policy, Property, Value);
|
||||
+ EXPECT_EQ(Value, clang_PrintingPolicy_getProperty(Policy, Property));
|
||||
+ }
|
||||
+ }
|
||||
+}
|
@@ -1,148 +0,0 @@
|
||||
--- a/tools/clang/include/clang/Sema/Sema.h
|
||||
+++ b/tools/clang/include/clang/Sema/Sema.h
|
||||
@@ -2707,7 +2707,8 @@
|
||||
OverloadCandidateSet &CandidateSet,
|
||||
TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr,
|
||||
bool SuppressUserConversions = false,
|
||||
- bool PartialOverloading = false);
|
||||
+ bool PartialOverloading = false,
|
||||
+ bool FirstArgumentIsBase = false);
|
||||
void AddMethodCandidate(DeclAccessPair FoundDecl,
|
||||
QualType ObjectType,
|
||||
Expr::Classification ObjectClassification,
|
||||
--- a/tools/clang/lib/Sema/SemaCodeComplete.cpp
|
||||
+++ b/tools/clang/lib/Sema/SemaCodeComplete.cpp
|
||||
@@ -4396,9 +4396,11 @@
|
||||
ArgExprs.append(Args.begin(), Args.end());
|
||||
UnresolvedSet<8> Decls;
|
||||
Decls.append(UME->decls_begin(), UME->decls_end());
|
||||
+ const bool FirstArgumentIsBase = !UME->isImplicitAccess() && UME->getBase();
|
||||
AddFunctionCandidates(Decls, ArgExprs, CandidateSet, TemplateArgs,
|
||||
/*SuppressUsedConversions=*/false,
|
||||
- /*PartialOverloading=*/true);
|
||||
+ /*PartialOverloading=*/true,
|
||||
+ FirstArgumentIsBase);
|
||||
} else {
|
||||
FunctionDecl *FD = nullptr;
|
||||
if (auto MCE = dyn_cast<MemberExpr>(NakedFn))
|
||||
--- a/tools/clang/lib/Sema/SemaOverload.cpp
|
||||
+++ b/tools/clang/lib/Sema/SemaOverload.cpp
|
||||
@@ -6343,24 +6343,36 @@
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
TemplateArgumentListInfo *ExplicitTemplateArgs,
|
||||
bool SuppressUserConversions,
|
||||
- bool PartialOverloading) {
|
||||
+ bool PartialOverloading,
|
||||
+ bool FirstArgumentIsBase) {
|
||||
for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) {
|
||||
NamedDecl *D = F.getDecl()->getUnderlyingDecl();
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
+ ArrayRef<Expr *> FunctionArgs = Args;
|
||||
if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) {
|
||||
QualType ObjectType;
|
||||
Expr::Classification ObjectClassification;
|
||||
- if (Expr *E = Args[0]) {
|
||||
- // Use the explit base to restrict the lookup:
|
||||
- ObjectType = E->getType();
|
||||
- ObjectClassification = E->Classify(Context);
|
||||
- } // .. else there is an implit base.
|
||||
+ if (Args.size() > 0) {
|
||||
+ if (Expr *E = Args[0]) {
|
||||
+ // Use the explit base to restrict the lookup:
|
||||
+ ObjectType = E->getType();
|
||||
+ ObjectClassification = E->Classify(Context);
|
||||
+ } // .. else there is an implit base.
|
||||
+ FunctionArgs = Args.slice(1);
|
||||
+ }
|
||||
AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(),
|
||||
cast<CXXMethodDecl>(FD)->getParent(), ObjectType,
|
||||
- ObjectClassification, Args.slice(1), CandidateSet,
|
||||
+ ObjectClassification, FunctionArgs, CandidateSet,
|
||||
SuppressUserConversions, PartialOverloading);
|
||||
} else {
|
||||
- AddOverloadCandidate(FD, F.getPair(), Args, CandidateSet,
|
||||
+ // Slice the first argument (which is the base) when we access
|
||||
+ // static method as non-static
|
||||
+ if (Args.size() > 0 && (!Args[0] || (FirstArgumentIsBase && isa<CXXMethodDecl>(FD) &&
|
||||
+ !isa<CXXConstructorDecl>(FD)))) {
|
||||
+ assert(cast<CXXMethodDecl>(FD)->isStatic());
|
||||
+ FunctionArgs = Args.slice(1);
|
||||
+ }
|
||||
+ AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet,
|
||||
SuppressUserConversions, PartialOverloading);
|
||||
}
|
||||
} else {
|
||||
--- a/tools/clang/test/Index/complete-call.cpp
|
||||
+++ b/tools/clang/test/Index/complete-call.cpp
|
||||
@@ -94,6 +94,24 @@
|
||||
s.foo_7(42,);
|
||||
}
|
||||
|
||||
+struct Bar {
|
||||
+ static void foo_1();
|
||||
+ void foo_1(float);
|
||||
+ static void foo_1(int);
|
||||
+};
|
||||
+
|
||||
+void test() {
|
||||
+ Bar::foo_1();
|
||||
+ Bar b;
|
||||
+ b.foo_1();
|
||||
+}
|
||||
+
|
||||
+struct Bar2 : public Bar {
|
||||
+ Bar2() {
|
||||
+ Bar::foo_1();
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
// RUN: c-index-test -code-completion-at=%s:47:9 %s | FileCheck -check-prefix=CHECK-CC1 %s
|
||||
// CHECK-CC1: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1)
|
||||
// CHECK-CC1: Completion contexts:
|
||||
@@ -803,3 +821,46 @@
|
||||
// CHECK-CC59-NEXT: Class name
|
||||
// CHECK-CC59-NEXT: Nested name specifier
|
||||
// CHECK-CC59-NEXT: Objective-C interface
|
||||
+
|
||||
+// RUN: c-index-test -code-completion-at=%s:104:14 %s | FileCheck -check-prefix=CHECK-CC60 %s
|
||||
+// CHECK-CC60: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1)
|
||||
+// CHECK-CC60: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter float}{RightParen )} (1)
|
||||
+// CHECK-CC60: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter int}{RightParen )} (1)
|
||||
+// CHECK-CC60: Completion contexts:
|
||||
+// CHECK-CC60-NEXT: Any type
|
||||
+// CHECK-CC60-NEXT: Any value
|
||||
+// CHECK-CC60-NEXT: Enum tag
|
||||
+// CHECK-CC60-NEXT: Union tag
|
||||
+// CHECK-CC60-NEXT: Struct tag
|
||||
+// CHECK-CC60-NEXT: Class name
|
||||
+// CHECK-CC60-NEXT: Nested name specifier
|
||||
+// CHECK-CC60-NEXT: Objective-C interface
|
||||
+
|
||||
+// RUN: c-index-test -code-completion-at=%s:106:11 %s | FileCheck -check-prefix=CHECK-CC61 %s
|
||||
+// CHECK-CC61: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1)
|
||||
+// CHECK-CC61: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter float}{RightParen )} (1)
|
||||
+// CHECK-CC61: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter int}{RightParen )} (1)
|
||||
+// CHECK-CC61: Completion contexts:
|
||||
+// CHECK-CC61-NEXT: Any type
|
||||
+// CHECK-CC61-NEXT: Any value
|
||||
+// CHECK-CC61-NEXT: Enum tag
|
||||
+// CHECK-CC61-NEXT: Union tag
|
||||
+// CHECK-CC61-NEXT: Struct tag
|
||||
+// CHECK-CC61-NEXT: Class name
|
||||
+// CHECK-CC61-NEXT: Nested name specifier
|
||||
+// CHECK-CC61-NEXT: Objective-C interface
|
||||
+
|
||||
+// RUN: c-index-test -code-completion-at=%s:111:16 %s | FileCheck -check-prefix=CHECK-CC62 %s
|
||||
+// CHECK-CC62: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1)
|
||||
+// CHECK-CC62: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter float}{RightParen )} (1)
|
||||
+// CHECK-CC62: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter int}{RightParen )} (1)
|
||||
+// CHECK-CC62: Completion contexts:
|
||||
+// CHECK-CC62-NEXT: Any type
|
||||
+// CHECK-CC62-NEXT: Any value
|
||||
+// CHECK-CC62-NEXT: Enum tag
|
||||
+// CHECK-CC62-NEXT: Union tag
|
||||
+// CHECK-CC62-NEXT: Struct tag
|
||||
+// CHECK-CC62-NEXT: Class name
|
||||
+// CHECK-CC62-NEXT: Nested name specifier
|
||||
+// CHECK-CC62-NEXT: Objective-C interface
|
||||
+
|
@@ -1,165 +0,0 @@
|
||||
diff --git a/tools/clang/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
|
||||
index 1b07ec60ce..46ed08d1cf 100644
|
||||
--- a/tools/clang/lib/Sema/SemaOverload.cpp
|
||||
+++ b/tools/clang/lib/Sema/SemaOverload.cpp
|
||||
@@ -6321,57 +6321,56 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
|
||||
bool FirstArgumentIsBase) {
|
||||
for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) {
|
||||
NamedDecl *D = F.getDecl()->getUnderlyingDecl();
|
||||
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
- ArrayRef<Expr *> FunctionArgs = Args;
|
||||
- if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) {
|
||||
- QualType ObjectType;
|
||||
- Expr::Classification ObjectClassification;
|
||||
- if (Args.size() > 0) {
|
||||
- if (Expr *E = Args[0]) {
|
||||
- // Use the explit base to restrict the lookup:
|
||||
- ObjectType = E->getType();
|
||||
- ObjectClassification = E->Classify(Context);
|
||||
- } // .. else there is an implit base.
|
||||
- FunctionArgs = Args.slice(1);
|
||||
- }
|
||||
- AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(),
|
||||
- cast<CXXMethodDecl>(FD)->getParent(), ObjectType,
|
||||
- ObjectClassification, FunctionArgs, CandidateSet,
|
||||
- SuppressUserConversions, PartialOverloading);
|
||||
- } else {
|
||||
- // Slice the first argument (which is the base) when we access
|
||||
- // static method as non-static
|
||||
- if (Args.size() > 0 && (!Args[0] || (FirstArgumentIsBase && isa<CXXMethodDecl>(FD) &&
|
||||
- !isa<CXXConstructorDecl>(FD)))) {
|
||||
- assert(cast<CXXMethodDecl>(FD)->isStatic());
|
||||
- FunctionArgs = Args.slice(1);
|
||||
- }
|
||||
- AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet,
|
||||
- SuppressUserConversions, PartialOverloading);
|
||||
- }
|
||||
- } else {
|
||||
- FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(D);
|
||||
- if (isa<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) &&
|
||||
- !cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic()) {
|
||||
- QualType ObjectType;
|
||||
- Expr::Classification ObjectClassification;
|
||||
+ ArrayRef<Expr *> FunctionArgs = Args;
|
||||
+
|
||||
+ FunctionTemplateDecl *FunTmpl = nullptr;
|
||||
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
|
||||
+
|
||||
+ const bool IsTemplate = FD ? false : true;
|
||||
+ if (IsTemplate) {
|
||||
+ FunTmpl = cast<FunctionTemplateDecl>(D);
|
||||
+ FD = FunTmpl->getTemplatedDecl();
|
||||
+ }
|
||||
+
|
||||
+ if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) {
|
||||
+ QualType ObjectType;
|
||||
+ Expr::Classification ObjectClassification;
|
||||
+ if (Args.size() > 0) {
|
||||
if (Expr *E = Args[0]) {
|
||||
// Use the explit base to restrict the lookup:
|
||||
ObjectType = E->getType();
|
||||
ObjectClassification = E->Classify(Context);
|
||||
} // .. else there is an implit base.
|
||||
+ FunctionArgs = Args.slice(1);
|
||||
+ }
|
||||
+ if (IsTemplate)
|
||||
AddMethodTemplateCandidate(
|
||||
FunTmpl, F.getPair(),
|
||||
cast<CXXRecordDecl>(FunTmpl->getDeclContext()),
|
||||
ExplicitTemplateArgs, ObjectType, ObjectClassification,
|
||||
- Args.slice(1), CandidateSet, SuppressUserConversions,
|
||||
+ FunctionArgs, CandidateSet, SuppressUserConversions,
|
||||
PartialOverloading);
|
||||
- } else {
|
||||
- AddTemplateOverloadCandidate(FunTmpl, F.getPair(),
|
||||
- ExplicitTemplateArgs, Args,
|
||||
- CandidateSet, SuppressUserConversions,
|
||||
- PartialOverloading);
|
||||
+ else
|
||||
+ AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(),
|
||||
+ cast<CXXMethodDecl>(FD)->getParent(), ObjectType,
|
||||
+ ObjectClassification, FunctionArgs, CandidateSet,
|
||||
+ SuppressUserConversions, PartialOverloading);
|
||||
+ } else {
|
||||
+ // Slice the first argument (which is the base) when we access
|
||||
+ // static method as non-static
|
||||
+ if (Args.size() > 0 &&
|
||||
+ (!Args[0] || (FirstArgumentIsBase && isa<CXXMethodDecl>(FD) &&
|
||||
+ !isa<CXXConstructorDecl>(FD)))) {
|
||||
+ assert(cast<CXXMethodDecl>(FD)->isStatic());
|
||||
+ FunctionArgs = Args.slice(1);
|
||||
}
|
||||
+ if (IsTemplate)
|
||||
+ AddTemplateOverloadCandidate(
|
||||
+ FunTmpl, F.getPair(), ExplicitTemplateArgs, FunctionArgs,
|
||||
+ CandidateSet, SuppressUserConversions, PartialOverloading);
|
||||
+ else
|
||||
+ AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet,
|
||||
+ SuppressUserConversions, PartialOverloading);
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/tools/clang/test/Index/complete-call.cpp b/test/Index/complete-call.cpp
|
||||
index ca116485ac..35f2009066 100644
|
||||
--- a/tools/clang/test/Index/complete-call.cpp
|
||||
+++ b/tools/clang/test/Index/complete-call.cpp
|
||||
@@ -112,6 +112,33 @@ struct Bar2 : public Bar {
|
||||
}
|
||||
};
|
||||
|
||||
+struct BarTemplates {
|
||||
+ static void foo_1() {}
|
||||
+ void foo_1(float) {}
|
||||
+ static void foo_1(int) {}
|
||||
+
|
||||
+ template<class T1, class T2>
|
||||
+ static void foo_1(T1 a, T2 b) { a + b; }
|
||||
+
|
||||
+ template<class T1, class T2>
|
||||
+ void foo_1(T1 a, T2 b, float c) { a + b + c; }
|
||||
+
|
||||
+ template<class T1, class T2>
|
||||
+ static void foo_1(T2 a, int b, T1 c) { a + b + c; }
|
||||
+};
|
||||
+
|
||||
+void testTemplates() {
|
||||
+ BarTemplates::foo_1();
|
||||
+ BarTemplates b;
|
||||
+ b.foo_1();
|
||||
+}
|
||||
+
|
||||
+struct Bar2Template : public BarTemplates {
|
||||
+ Bar2Template() {
|
||||
+ BarTemplates::foo_1();
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
// RUN: c-index-test -code-completion-at=%s:47:9 %s | FileCheck -check-prefix=CHECK-CC1 %s
|
||||
// CHECK-CC1: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1)
|
||||
// CHECK-CC1: Completion contexts:
|
||||
@@ -864,3 +891,25 @@ struct Bar2 : public Bar {
|
||||
// CHECK-CC62-NEXT: Nested name specifier
|
||||
// CHECK-CC62-NEXT: Objective-C interface
|
||||
|
||||
+// RUN: c-index-test -code-completion-at=%s:131:23 %s | FileCheck -check-prefix=CHECK-CC63 %s
|
||||
+// CHECK-CC63: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1)
|
||||
+// CHECK-CC63: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter float}{RightParen )} (1)
|
||||
+// CHECK-CC63: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter int}{RightParen )} (1)
|
||||
+// CHECK-CC63: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter T1 a}{Comma , }{Placeholder T2 b}{RightParen )} (1)
|
||||
+// CHECK-CC63: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter T1 a}{Comma , }{Placeholder T2 b}{Comma , }{Placeholder float c}{RightParen )} (1)
|
||||
+// CHECK-CC63: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter T2 a}{Comma , }{Placeholder int b}{Comma , }{Placeholder T1 c}{RightParen )} (1)
|
||||
+
|
||||
+// RUN: c-index-test -code-completion-at=%s:133:11 %s | FileCheck -check-prefix=CHECK-CC64 %s
|
||||
+// CHECK-CC64: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1)
|
||||
+// CHECK-CC64: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter float}{RightParen )} (1)
|
||||
+// CHECK-CC64: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter int}{RightParen )} (1)
|
||||
+// CHECK-CC64: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter T1 a}{Comma , }{Placeholder T2 b}{RightParen )} (1)
|
||||
+// CHECK-CC64: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter T2 a}{Comma , }{Placeholder int b}{Comma , }{Placeholder T1 c}{RightParen )} (1)
|
||||
+
|
||||
+// RUN: c-index-test -code-completion-at=%s:138:25 %s | FileCheck -check-prefix=CHECK-CC65 %s
|
||||
+// CHECK-CC65: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1)
|
||||
+// CHECK-CC65: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter float}{RightParen )} (1)
|
||||
+// CHECK-CC65: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter int}{RightParen )} (1)
|
||||
+// CHECK-CC65: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter T1 a}{Comma , }{Placeholder T2 b}{RightParen )} (1)
|
||||
+// CHECK-CC65: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter T1 a}{Comma , }{Placeholder T2 b}{Comma , }{Placeholder float c}{RightParen )} (1)
|
||||
+// CHECK-CC65: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter T2 a}{Comma , }{Placeholder int b}{Comma , }{Placeholder T1 c}{RightParen )} (1)
|
@@ -1,739 +0,0 @@
|
||||
diff --git a/tools/clang/include/clang/AST/ASTContext.h b/tools/clang/include/clang/AST/ASTContext.h
|
||||
index 703f588c56..d7beffa25e 100644
|
||||
--- a/tools/clang/include/clang/AST/ASTContext.h
|
||||
+++ b/tools/clang/include/clang/AST/ASTContext.h
|
||||
@@ -2072,6 +2072,10 @@ public:
|
||||
void CollectInheritedProtocols(const Decl *CDecl,
|
||||
llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols);
|
||||
|
||||
+ /// \brief Return true if the specified type has unique object representations
|
||||
+ /// according to (C++17 [meta.unary.prop]p9)
|
||||
+ bool hasUniqueObjectRepresentations(QualType Ty) const;
|
||||
+
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Operators
|
||||
//===--------------------------------------------------------------------===//
|
||||
diff --git a/tools/clang/include/clang/Basic/TokenKinds.def b/tools/clang/include/clang/Basic/TokenKinds.def
|
||||
index be67663a10..90ac33b9ea 100644
|
||||
--- a/tools/clang/include/clang/Basic/TokenKinds.def
|
||||
+++ b/tools/clang/include/clang/Basic/TokenKinds.def
|
||||
@@ -448,6 +448,8 @@ TYPE_TRAIT_1(__is_pod, IsPOD, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_polymorphic, IsPolymorphic, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_trivial, IsTrivial, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX)
|
||||
+TYPE_TRAIT_1(__has_unique_object_representations,
|
||||
+ HasUniqueObjectRepresentations, KEYCXX)
|
||||
|
||||
// Clang-only C++ Type Traits
|
||||
TYPE_TRAIT_N(__is_trivially_constructible, IsTriviallyConstructible, KEYCXX)
|
||||
diff --git a/tools/clang/include/clang/Basic/TypeTraits.h b/tools/clang/include/clang/Basic/TypeTraits.h
|
||||
index 6aadf795d8..8ecd63f9c3 100644
|
||||
--- a/tools/clang/include/clang/Basic/TypeTraits.h
|
||||
+++ b/tools/clang/include/clang/Basic/TypeTraits.h
|
||||
@@ -70,7 +70,8 @@ namespace clang {
|
||||
UTT_IsUnsigned,
|
||||
UTT_IsVoid,
|
||||
UTT_IsVolatile,
|
||||
- UTT_Last = UTT_IsVolatile,
|
||||
+ UTT_HasUniqueObjectRepresentations,
|
||||
+ UTT_Last = UTT_HasUniqueObjectRepresentations,
|
||||
BTT_IsBaseOf,
|
||||
BTT_IsConvertible,
|
||||
BTT_IsConvertibleTo,
|
||||
diff --git a/tools/clang/lib/AST/ASTContext.cpp b/tools/clang/lib/AST/ASTContext.cpp
|
||||
index c60373c5a9..1ce7d51857 100644
|
||||
--- a/tools/clang/lib/AST/ASTContext.cpp
|
||||
+++ b/tools/clang/lib/AST/ASTContext.cpp
|
||||
@@ -1823,7 +1823,9 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
|
||||
}
|
||||
case Type::MemberPointer: {
|
||||
const MemberPointerType *MPT = cast<MemberPointerType>(T);
|
||||
- std::tie(Width, Align) = ABI->getMemberPointerWidthAndAlign(MPT);
|
||||
+ CXXABI::MemberPointerInfo MPI = ABI->getMemberPointerInfo(MPT);
|
||||
+ Width = MPI.Width;
|
||||
+ Align = MPI.Align;
|
||||
break;
|
||||
}
|
||||
case Type::Complex: {
|
||||
@@ -2107,6 +2109,171 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
|
||||
}
|
||||
}
|
||||
|
||||
+static bool unionHasUniqueObjectRepresentations(const ASTContext &Context,
|
||||
+ const RecordDecl *RD) {
|
||||
+ assert(RD->isUnion() && "Must be union type");
|
||||
+ CharUnits UnionSize = Context.getTypeSizeInChars(RD->getTypeForDecl());
|
||||
+
|
||||
+ for (const auto *Field : RD->fields()) {
|
||||
+ if (!Context.hasUniqueObjectRepresentations(Field->getType()))
|
||||
+ return false;
|
||||
+ CharUnits FieldSize = Context.getTypeSizeInChars(Field->getType());
|
||||
+ if (FieldSize != UnionSize)
|
||||
+ return false;
|
||||
+ }
|
||||
+ return !RD->field_empty();
|
||||
+}
|
||||
+
|
||||
+bool isStructEmpty(QualType Ty) {
|
||||
+ const RecordDecl *RD = Ty->castAs<RecordType>()->getDecl();
|
||||
+
|
||||
+ if (!RD->field_empty())
|
||||
+ return false;
|
||||
+
|
||||
+ if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD))
|
||||
+ return ClassDecl->isEmpty();
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+static llvm::Optional<int64_t>
|
||||
+structHasUniqueObjectRepresentations(const ASTContext &Context,
|
||||
+ const RecordDecl *RD) {
|
||||
+ assert(!RD->isUnion() && "Must be struct/class type");
|
||||
+ const auto &Layout = Context.getASTRecordLayout(RD);
|
||||
+
|
||||
+ int64_t CurOffsetInBits = 0;
|
||||
+ if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) {
|
||||
+ if (ClassDecl->isDynamicClass())
|
||||
+ return llvm::None;
|
||||
+
|
||||
+ SmallVector<std::pair<QualType, int64_t>, 4> Bases;
|
||||
+ for (const auto Base : ClassDecl->bases()) {
|
||||
+ // Empty types can be inherited from, and non-empty types can potentially
|
||||
+ // have tail padding, so just make sure there isn't an error.
|
||||
+ if (!isStructEmpty(Base.getType())) {
|
||||
+ llvm::Optional<int64_t> Size = structHasUniqueObjectRepresentations(
|
||||
+ Context, Base.getType()->getAs<RecordType>()->getDecl());
|
||||
+ if (!Size)
|
||||
+ return llvm::None;
|
||||
+ Bases.emplace_back(Base.getType(), Size.getValue());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ std::sort(
|
||||
+ Bases.begin(), Bases.end(), [&](const std::pair<QualType, int64_t> &L,
|
||||
+ const std::pair<QualType, int64_t> &R) {
|
||||
+ return Layout.getBaseClassOffset(L.first->getAsCXXRecordDecl()) <
|
||||
+ Layout.getBaseClassOffset(R.first->getAsCXXRecordDecl());
|
||||
+ });
|
||||
+
|
||||
+ for (const auto Base : Bases) {
|
||||
+ int64_t BaseOffset = Context.toBits(
|
||||
+ Layout.getBaseClassOffset(Base.first->getAsCXXRecordDecl()));
|
||||
+ int64_t BaseSize = Base.second;
|
||||
+ if (BaseOffset != CurOffsetInBits)
|
||||
+ return llvm::None;
|
||||
+ CurOffsetInBits = BaseOffset + BaseSize;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (const auto *Field : RD->fields()) {
|
||||
+ if (!Field->getType()->isReferenceType() &&
|
||||
+ !Context.hasUniqueObjectRepresentations(Field->getType()))
|
||||
+ return llvm::None;
|
||||
+
|
||||
+ int64_t FieldSizeInBits =
|
||||
+ Context.toBits(Context.getTypeSizeInChars(Field->getType()));
|
||||
+ if (Field->isBitField()) {
|
||||
+ int64_t BitfieldSize = Field->getBitWidthValue(Context);
|
||||
+
|
||||
+ if (BitfieldSize > FieldSizeInBits)
|
||||
+ return llvm::None;
|
||||
+ FieldSizeInBits = BitfieldSize;
|
||||
+ }
|
||||
+
|
||||
+ int64_t FieldOffsetInBits = Context.getFieldOffset(Field);
|
||||
+
|
||||
+ if (FieldOffsetInBits != CurOffsetInBits)
|
||||
+ return llvm::None;
|
||||
+
|
||||
+ CurOffsetInBits = FieldSizeInBits + FieldOffsetInBits;
|
||||
+ }
|
||||
+
|
||||
+ return CurOffsetInBits;
|
||||
+}
|
||||
+
|
||||
+bool ASTContext::hasUniqueObjectRepresentations(QualType Ty) const {
|
||||
+ // C++17 [meta.unary.prop]:
|
||||
+ // The predicate condition for a template specialization
|
||||
+ // has_unique_object_representations<T> shall be
|
||||
+ // satisfied if and only if:
|
||||
+ // (9.1) - T is trivially copyable, and
|
||||
+ // (9.2) - any two objects of type T with the same value have the same
|
||||
+ // object representation, where two objects
|
||||
+ // of array or non-union class type are considered to have the same value
|
||||
+ // if their respective sequences of
|
||||
+ // direct subobjects have the same values, and two objects of union type
|
||||
+ // are considered to have the same
|
||||
+ // value if they have the same active member and the corresponding members
|
||||
+ // have the same value.
|
||||
+ // The set of scalar types for which this condition holds is
|
||||
+ // implementation-defined. [ Note: If a type has padding
|
||||
+ // bits, the condition does not hold; otherwise, the condition holds true
|
||||
+ // for unsigned integral types. -- end note ]
|
||||
+ assert(!Ty.isNull() && "Null QualType sent to unique object rep check");
|
||||
+
|
||||
+ // Arrays are unique only if their element type is unique.
|
||||
+ if (Ty->isArrayType())
|
||||
+ return hasUniqueObjectRepresentations(getBaseElementType(Ty));
|
||||
+
|
||||
+ // (9.1) - T is trivially copyable...
|
||||
+ if (!Ty.isTriviallyCopyableType(*this))
|
||||
+ return false;
|
||||
+
|
||||
+ // All integrals and enums are unique.
|
||||
+ if (Ty->isIntegralOrEnumerationType())
|
||||
+ return true;
|
||||
+
|
||||
+ // All other pointers are unique.
|
||||
+ if (Ty->isPointerType())
|
||||
+ return true;
|
||||
+
|
||||
+ if (Ty->isMemberPointerType()) {
|
||||
+ const MemberPointerType *MPT = Ty->getAs<MemberPointerType>();
|
||||
+ return !ABI->getMemberPointerInfo(MPT).HasPadding;
|
||||
+ }
|
||||
+
|
||||
+ if (Ty->isRecordType()) {
|
||||
+ const RecordDecl *Record = Ty->getAs<RecordType>()->getDecl();
|
||||
+
|
||||
+ if (Record->isInvalidDecl())
|
||||
+ return false;
|
||||
+
|
||||
+ if (Record->isUnion())
|
||||
+ return unionHasUniqueObjectRepresentations(*this, Record);
|
||||
+
|
||||
+ Optional<int64_t> StructSize =
|
||||
+ structHasUniqueObjectRepresentations(*this, Record);
|
||||
+
|
||||
+ return StructSize &&
|
||||
+ StructSize.getValue() == static_cast<int64_t>(getTypeSize(Ty));
|
||||
+ }
|
||||
+
|
||||
+ // FIXME: More cases to handle here (list by rsmith):
|
||||
+ // vectors (careful about, eg, vector of 3 foo)
|
||||
+ // _Complex int and friends
|
||||
+ // _Atomic T
|
||||
+ // Obj-C block pointers
|
||||
+ // Obj-C object pointers
|
||||
+ // and perhaps OpenCL's various builtin types (pipe, sampler_t, event_t,
|
||||
+ // clk_event_t, queue_t, reserve_id_t)
|
||||
+ // There're also Obj-C class types and the Obj-C selector type, but I think it
|
||||
+ // makes sense for those to return false here.
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) const {
|
||||
unsigned count = 0;
|
||||
// Count ivars declared in class extension.
|
||||
diff --git a/tools/clang/lib/AST/CXXABI.h b/tools/clang/lib/AST/CXXABI.h
|
||||
index 924ef00e81..06295b5817 100644
|
||||
--- a/tools/clang/lib/AST/CXXABI.h
|
||||
+++ b/tools/clang/lib/AST/CXXABI.h
|
||||
@@ -31,9 +31,16 @@ class CXXABI {
|
||||
public:
|
||||
virtual ~CXXABI();
|
||||
|
||||
- /// Returns the width and alignment of a member pointer in bits.
|
||||
- virtual std::pair<uint64_t, unsigned>
|
||||
- getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const = 0;
|
||||
+ struct MemberPointerInfo {
|
||||
+ uint64_t Width;
|
||||
+ unsigned Align;
|
||||
+ bool HasPadding;
|
||||
+ };
|
||||
+
|
||||
+ /// Returns the width and alignment of a member pointer in bits, as well as
|
||||
+ /// whether it has padding.
|
||||
+ virtual MemberPointerInfo
|
||||
+ getMemberPointerInfo(const MemberPointerType *MPT) const = 0;
|
||||
|
||||
/// Returns the default calling convention for C++ methods.
|
||||
virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0;
|
||||
diff --git a/tools/clang/lib/AST/ItaniumCXXABI.cpp b/tools/clang/lib/AST/ItaniumCXXABI.cpp
|
||||
index 692a455eaf..d6bc16b635 100644
|
||||
--- a/tools/clang/lib/AST/ItaniumCXXABI.cpp
|
||||
+++ b/tools/clang/lib/AST/ItaniumCXXABI.cpp
|
||||
@@ -101,15 +101,17 @@ protected:
|
||||
public:
|
||||
ItaniumCXXABI(ASTContext &Ctx) : Context(Ctx) { }
|
||||
|
||||
- std::pair<uint64_t, unsigned>
|
||||
- getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const override {
|
||||
+ MemberPointerInfo
|
||||
+ getMemberPointerInfo(const MemberPointerType *MPT) const override {
|
||||
const TargetInfo &Target = Context.getTargetInfo();
|
||||
TargetInfo::IntType PtrDiff = Target.getPtrDiffType(0);
|
||||
- uint64_t Width = Target.getTypeWidth(PtrDiff);
|
||||
- unsigned Align = Target.getTypeAlign(PtrDiff);
|
||||
+ MemberPointerInfo MPI;
|
||||
+ MPI.Width = Target.getTypeWidth(PtrDiff);
|
||||
+ MPI.Align = Target.getTypeAlign(PtrDiff);
|
||||
+ MPI.HasPadding = false;
|
||||
if (MPT->isMemberFunctionPointer())
|
||||
- Width = 2 * Width;
|
||||
- return std::make_pair(Width, Align);
|
||||
+ MPI.Width *= 2;
|
||||
+ return MPI;
|
||||
}
|
||||
|
||||
CallingConv getDefaultMethodCallConv(bool isVariadic) const override {
|
||||
diff --git a/tools/clang/lib/AST/MicrosoftCXXABI.cpp b/tools/clang/lib/AST/MicrosoftCXXABI.cpp
|
||||
index 73324e40f3..b19491f313 100644
|
||||
--- a/tools/clang/lib/AST/MicrosoftCXXABI.cpp
|
||||
+++ b/tools/clang/lib/AST/MicrosoftCXXABI.cpp
|
||||
@@ -76,8 +76,8 @@ class MicrosoftCXXABI : public CXXABI {
|
||||
public:
|
||||
MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { }
|
||||
|
||||
- std::pair<uint64_t, unsigned>
|
||||
- getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const override;
|
||||
+ MemberPointerInfo
|
||||
+ getMemberPointerInfo(const MemberPointerType *MPT) const override;
|
||||
|
||||
CallingConv getDefaultMethodCallConv(bool isVariadic) const override {
|
||||
if (!isVariadic &&
|
||||
@@ -227,7 +227,7 @@ getMSMemberPointerSlots(const MemberPointerType *MPT) {
|
||||
return std::make_pair(Ptrs, Ints);
|
||||
}
|
||||
|
||||
-std::pair<uint64_t, unsigned> MicrosoftCXXABI::getMemberPointerWidthAndAlign(
|
||||
+CXXABI::MemberPointerInfo MicrosoftCXXABI::getMemberPointerInfo(
|
||||
const MemberPointerType *MPT) const {
|
||||
// The nominal struct is laid out with pointers followed by ints and aligned
|
||||
// to a pointer width if any are present and an int width otherwise.
|
||||
@@ -237,22 +237,25 @@ std::pair<uint64_t, unsigned> MicrosoftCXXABI::getMemberPointerWidthAndAlign(
|
||||
|
||||
unsigned Ptrs, Ints;
|
||||
std::tie(Ptrs, Ints) = getMSMemberPointerSlots(MPT);
|
||||
- uint64_t Width = Ptrs * PtrSize + Ints * IntSize;
|
||||
- unsigned Align;
|
||||
+ MemberPointerInfo MPI;
|
||||
+ MPI.HasPadding = false;
|
||||
+ MPI.Width = Ptrs * PtrSize + Ints * IntSize;
|
||||
|
||||
// When MSVC does x86_32 record layout, it aligns aggregate member pointers to
|
||||
// 8 bytes. However, __alignof usually returns 4 for data memptrs and 8 for
|
||||
// function memptrs.
|
||||
if (Ptrs + Ints > 1 && Target.getTriple().isArch32Bit())
|
||||
- Align = 64;
|
||||
+ MPI.Align = 64;
|
||||
else if (Ptrs)
|
||||
- Align = Target.getPointerAlign(0);
|
||||
+ MPI.Align = Target.getPointerAlign(0);
|
||||
else
|
||||
- Align = Target.getIntAlign();
|
||||
+ MPI.Align = Target.getIntAlign();
|
||||
|
||||
- if (Target.getTriple().isArch64Bit())
|
||||
- Width = llvm::alignTo(Width, Align);
|
||||
- return std::make_pair(Width, Align);
|
||||
+ if (Target.getTriple().isArch64Bit()) {
|
||||
+ MPI.Width = llvm::alignTo(MPI.Width, MPI.Align);
|
||||
+ MPI.HasPadding = MPI.Width != (Ptrs * PtrSize + Ints * IntSize);
|
||||
+ }
|
||||
+ return MPI;
|
||||
}
|
||||
|
||||
CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) {
|
||||
diff --git a/tools/clang/lib/Parse/ParseExpr.cpp b/tools/clang/lib/Parse/ParseExpr.cpp
|
||||
index 44b87af01a..73aac10c23 100644
|
||||
--- a/tools/clang/lib/Parse/ParseExpr.cpp
|
||||
+++ b/tools/clang/lib/Parse/ParseExpr.cpp
|
||||
@@ -716,6 +716,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback {
|
||||
/// '__is_sealed' [MS]
|
||||
/// '__is_trivial'
|
||||
/// '__is_union'
|
||||
+/// '__has_unique_object_representations'
|
||||
///
|
||||
/// [Clang] unary-type-trait:
|
||||
/// '__is_aggregate'
|
||||
diff --git a/tools/clang/lib/Sema/SemaExprCXX.cpp b/tools/clang/lib/Sema/SemaExprCXX.cpp
|
||||
index a9cf3ec799..a7d75ad977 100644
|
||||
--- a/tools/clang/lib/Sema/SemaExprCXX.cpp
|
||||
+++ b/tools/clang/lib/Sema/SemaExprCXX.cpp
|
||||
@@ -4141,6 +4141,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
|
||||
case UTT_IsDestructible:
|
||||
case UTT_IsNothrowDestructible:
|
||||
case UTT_IsTriviallyDestructible:
|
||||
+ case UTT_HasUniqueObjectRepresentations:
|
||||
if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType())
|
||||
return true;
|
||||
|
||||
@@ -4580,6 +4581,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
|
||||
// Returns True if and only if T is a complete type at the point of the
|
||||
// function call.
|
||||
return !T->isIncompleteType();
|
||||
+ case UTT_HasUniqueObjectRepresentations:
|
||||
+ return C.hasUniqueObjectRepresentations(T);
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/tools/clang/test/SemaCXX/has_unique_object_reps_member_ptr.cpp b/tools/clang/test/SemaCXX/has_unique_object_reps_member_ptr.cpp
|
||||
new file mode 100644
|
||||
index 0000000000..b8e27f82ff
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/SemaCXX/has_unique_object_reps_member_ptr.cpp
|
||||
@@ -0,0 +1,32 @@
|
||||
+// RUN: %clang_cc1 -triple x86_64-linux-pc -DIS64 -fsyntax-only -verify -std=c++17 %s
|
||||
+// RUN: %clang_cc1 -triple x86_64-windows-pc -DIS64 -fsyntax-only -verify -std=c++17 %s
|
||||
+// RUN: %clang_cc1 -triple i386-linux-pc -fsyntax-only -verify -std=c++17 %s
|
||||
+// RUN: %clang_cc1 -triple i386-windows-pc -DW32 -fsyntax-only -verify -std=c++17 %s
|
||||
+// expected-no-diagnostics
|
||||
+
|
||||
+struct Base {};
|
||||
+struct A : virtual Base {
|
||||
+ virtual void n() {}
|
||||
+};
|
||||
+
|
||||
+auto p = &A::n;
|
||||
+static_assert(__has_unique_object_representations(decltype(p)));
|
||||
+
|
||||
+struct B {
|
||||
+ decltype(p) x;
|
||||
+ int b;
|
||||
+#ifdef IS64
|
||||
+ // required on 64 bit to fill out the tail padding.
|
||||
+ int c;
|
||||
+#endif
|
||||
+};
|
||||
+static_assert(__has_unique_object_representations(B));
|
||||
+
|
||||
+struct C { // has padding on Win32, but nothing else.
|
||||
+ decltype(p) x;
|
||||
+};
|
||||
+#ifdef W32
|
||||
+static_assert(!__has_unique_object_representations(C));
|
||||
+#else
|
||||
+static_assert(__has_unique_object_representations(C));
|
||||
+#endif
|
||||
diff --git a/tools/clang/test/SemaCXX/type-traits.cpp b/tools/clang/test/SemaCXX/type-traits.cpp
|
||||
index 5879a77dd5..3c2f9c7f0f 100644
|
||||
--- a/tools/clang/test/SemaCXX/type-traits.cpp
|
||||
+++ b/tools/clang/test/SemaCXX/type-traits.cpp
|
||||
@@ -2352,3 +2352,321 @@ void is_trivially_destructible_test() {
|
||||
{ int arr[F(__is_trivially_destructible(void))]; }
|
||||
{ int arr[F(__is_trivially_destructible(const volatile void))]; }
|
||||
}
|
||||
+
|
||||
+// Instantiation of __has_unique_object_representations
|
||||
+template <typename T>
|
||||
+struct has_unique_object_representations {
|
||||
+ static const bool value = __has_unique_object_representations(T);
|
||||
+};
|
||||
+
|
||||
+static_assert(!has_unique_object_representations<void>::value, "void is never unique");
|
||||
+static_assert(!has_unique_object_representations<const void>::value, "void is never unique");
|
||||
+static_assert(!has_unique_object_representations<volatile void>::value, "void is never unique");
|
||||
+static_assert(!has_unique_object_representations<const volatile void>::value, "void is never unique");
|
||||
+
|
||||
+static_assert(has_unique_object_representations<int>::value, "integrals are");
|
||||
+static_assert(has_unique_object_representations<const int>::value, "integrals are");
|
||||
+static_assert(has_unique_object_representations<volatile int>::value, "integrals are");
|
||||
+static_assert(has_unique_object_representations<const volatile int>::value, "integrals are");
|
||||
+
|
||||
+static_assert(has_unique_object_representations<void *>::value, "as are pointers");
|
||||
+static_assert(has_unique_object_representations<const void *>::value, "as are pointers");
|
||||
+static_assert(has_unique_object_representations<volatile void *>::value, "are pointers");
|
||||
+static_assert(has_unique_object_representations<const volatile void *>::value, "as are pointers");
|
||||
+
|
||||
+static_assert(has_unique_object_representations<int *>::value, "as are pointers");
|
||||
+static_assert(has_unique_object_representations<const int *>::value, "as are pointers");
|
||||
+static_assert(has_unique_object_representations<volatile int *>::value, "as are pointers");
|
||||
+static_assert(has_unique_object_representations<const volatile int *>::value, "as are pointers");
|
||||
+
|
||||
+class C {};
|
||||
+using FP = int (*)(int);
|
||||
+using PMF = int (C::*)(int);
|
||||
+using PMD = int C::*;
|
||||
+
|
||||
+static_assert(has_unique_object_representations<FP>::value, "even function pointers");
|
||||
+static_assert(has_unique_object_representations<const FP>::value, "even function pointers");
|
||||
+static_assert(has_unique_object_representations<volatile FP>::value, "even function pointers");
|
||||
+static_assert(has_unique_object_representations<const volatile FP>::value, "even function pointers");
|
||||
+
|
||||
+static_assert(has_unique_object_representations<PMF>::value, "and pointer to members");
|
||||
+static_assert(has_unique_object_representations<const PMF>::value, "and pointer to members");
|
||||
+static_assert(has_unique_object_representations<volatile PMF>::value, "and pointer to members");
|
||||
+static_assert(has_unique_object_representations<const volatile PMF>::value, "and pointer to members");
|
||||
+
|
||||
+static_assert(has_unique_object_representations<PMD>::value, "and pointer to members");
|
||||
+static_assert(has_unique_object_representations<const PMD>::value, "and pointer to members");
|
||||
+static_assert(has_unique_object_representations<volatile PMD>::value, "and pointer to members");
|
||||
+static_assert(has_unique_object_representations<const volatile PMD>::value, "and pointer to members");
|
||||
+
|
||||
+static_assert(has_unique_object_representations<bool>::value, "yes, all integral types");
|
||||
+static_assert(has_unique_object_representations<char>::value, "yes, all integral types");
|
||||
+static_assert(has_unique_object_representations<signed char>::value, "yes, all integral types");
|
||||
+static_assert(has_unique_object_representations<unsigned char>::value, "yes, all integral types");
|
||||
+static_assert(has_unique_object_representations<short>::value, "yes, all integral types");
|
||||
+static_assert(has_unique_object_representations<unsigned short>::value, "yes, all integral types");
|
||||
+static_assert(has_unique_object_representations<int>::value, "yes, all integral types");
|
||||
+static_assert(has_unique_object_representations<unsigned int>::value, "yes, all integral types");
|
||||
+static_assert(has_unique_object_representations<long>::value, "yes, all integral types");
|
||||
+static_assert(has_unique_object_representations<unsigned long>::value, "yes, all integral types");
|
||||
+static_assert(has_unique_object_representations<long long>::value, "yes, all integral types");
|
||||
+static_assert(has_unique_object_representations<unsigned long long>::value, "yes, all integral types");
|
||||
+static_assert(has_unique_object_representations<wchar_t>::value, "yes, all integral types");
|
||||
+static_assert(has_unique_object_representations<char16_t>::value, "yes, all integral types");
|
||||
+static_assert(has_unique_object_representations<char32_t>::value, "yes, all integral types");
|
||||
+
|
||||
+static_assert(!has_unique_object_representations<void>::value, "but not void!");
|
||||
+static_assert(!has_unique_object_representations<decltype(nullptr)>::value, "or nullptr_t");
|
||||
+static_assert(!has_unique_object_representations<float>::value, "definitely not Floating Point");
|
||||
+static_assert(!has_unique_object_representations<double>::value, "definitely not Floating Point");
|
||||
+static_assert(!has_unique_object_representations<long double>::value, "definitely not Floating Point");
|
||||
+
|
||||
+struct NoPadding {
|
||||
+ int a;
|
||||
+ int b;
|
||||
+};
|
||||
+
|
||||
+static_assert(has_unique_object_representations<NoPadding>::value, "types without padding are");
|
||||
+
|
||||
+struct InheritsFromNoPadding : NoPadding {
|
||||
+ int c;
|
||||
+ int d;
|
||||
+};
|
||||
+
|
||||
+static_assert(has_unique_object_representations<InheritsFromNoPadding>::value, "types without padding are");
|
||||
+
|
||||
+struct VirtuallyInheritsFromNoPadding : virtual NoPadding {
|
||||
+ int c;
|
||||
+ int d;
|
||||
+};
|
||||
+
|
||||
+static_assert(!has_unique_object_representations<VirtuallyInheritsFromNoPadding>::value, "No virtual inheritence");
|
||||
+
|
||||
+struct Padding {
|
||||
+ char a;
|
||||
+ int b;
|
||||
+};
|
||||
+
|
||||
+//static_assert(!has_unique_object_representations<Padding>::value, "but not with padding");
|
||||
+
|
||||
+struct InheritsFromPadding : Padding {
|
||||
+ int c;
|
||||
+ int d;
|
||||
+};
|
||||
+
|
||||
+static_assert(!has_unique_object_representations<InheritsFromPadding>::value, "or its subclasses");
|
||||
+
|
||||
+struct TailPadding {
|
||||
+ int a;
|
||||
+ char b;
|
||||
+};
|
||||
+
|
||||
+static_assert(!has_unique_object_representations<TailPadding>::value, "even at the end");
|
||||
+
|
||||
+struct TinyStruct {
|
||||
+ char a;
|
||||
+};
|
||||
+
|
||||
+static_assert(has_unique_object_representations<TinyStruct>::value, "Should be no padding");
|
||||
+
|
||||
+struct InheritsFromTinyStruct : TinyStruct {
|
||||
+ int b;
|
||||
+};
|
||||
+
|
||||
+static_assert(!has_unique_object_representations<InheritsFromTinyStruct>::value, "Inherit causes padding");
|
||||
+
|
||||
+union NoPaddingUnion {
|
||||
+ int a;
|
||||
+ unsigned int b;
|
||||
+};
|
||||
+
|
||||
+static_assert(has_unique_object_representations<NoPaddingUnion>::value, "unions follow the same rules as structs");
|
||||
+
|
||||
+union PaddingUnion {
|
||||
+ int a;
|
||||
+ long long b;
|
||||
+};
|
||||
+
|
||||
+static_assert(!has_unique_object_representations<PaddingUnion>::value, "unions follow the same rules as structs");
|
||||
+
|
||||
+struct NotTriviallyCopyable {
|
||||
+ int x;
|
||||
+ NotTriviallyCopyable(const NotTriviallyCopyable &) {}
|
||||
+};
|
||||
+
|
||||
+static_assert(!has_unique_object_representations<NotTriviallyCopyable>::value, "must be trivially copyable");
|
||||
+
|
||||
+struct HasNonUniqueMember {
|
||||
+ float x;
|
||||
+};
|
||||
+
|
||||
+static_assert(!has_unique_object_representations<HasNonUniqueMember>::value, "all members must be unique");
|
||||
+
|
||||
+enum ExampleEnum { xExample,
|
||||
+ yExample };
|
||||
+enum LLEnum : long long { xLongExample,
|
||||
+ yLongExample };
|
||||
+
|
||||
+static_assert(has_unique_object_representations<ExampleEnum>::value, "Enums are integrals, so unique!");
|
||||
+static_assert(has_unique_object_representations<LLEnum>::value, "Enums are integrals, so unique!");
|
||||
+
|
||||
+enum class ExampleEnumClass { xExample,
|
||||
+ yExample };
|
||||
+enum class LLEnumClass : long long { xLongExample,
|
||||
+ yLongExample };
|
||||
+
|
||||
+static_assert(has_unique_object_representations<ExampleEnumClass>::value, "Enums are integrals, so unique!");
|
||||
+static_assert(has_unique_object_representations<LLEnumClass>::value, "Enums are integrals, so unique!");
|
||||
+
|
||||
+// because references aren't trivially copyable.
|
||||
+static_assert(!has_unique_object_representations<int &>::value, "No references!");
|
||||
+static_assert(!has_unique_object_representations<const int &>::value, "No references!");
|
||||
+static_assert(!has_unique_object_representations<volatile int &>::value, "No references!");
|
||||
+static_assert(!has_unique_object_representations<const volatile int &>::value, "No references!");
|
||||
+static_assert(!has_unique_object_representations<Empty>::value, "No empty types!");
|
||||
+static_assert(!has_unique_object_representations<EmptyUnion>::value, "No empty types!");
|
||||
+
|
||||
+class Compressed : Empty {
|
||||
+ int x;
|
||||
+};
|
||||
+
|
||||
+static_assert(has_unique_object_representations<Compressed>::value, "But inheriting from one is ok");
|
||||
+
|
||||
+class EmptyInheritor : Compressed {};
|
||||
+
|
||||
+static_assert(has_unique_object_representations<EmptyInheritor>::value, "As long as the base has items, empty is ok");
|
||||
+
|
||||
+class Dynamic {
|
||||
+ virtual void A();
|
||||
+ int i;
|
||||
+};
|
||||
+
|
||||
+static_assert(!has_unique_object_representations<Dynamic>::value, "Dynamic types are not valid");
|
||||
+
|
||||
+class InheritsDynamic : Dynamic {
|
||||
+ int j;
|
||||
+};
|
||||
+
|
||||
+static_assert(!has_unique_object_representations<InheritsDynamic>::value, "Dynamic types are not valid");
|
||||
+
|
||||
+static_assert(has_unique_object_representations<int[42]>::value, "Arrays are fine, as long as their value type is");
|
||||
+static_assert(has_unique_object_representations<int[]>::value, "Arrays are fine, as long as their value type is");
|
||||
+static_assert(has_unique_object_representations<int[][42]>::value, "Arrays are fine, as long as their value type is");
|
||||
+static_assert(!has_unique_object_representations<double[42]>::value, "So no array of doubles!");
|
||||
+static_assert(!has_unique_object_representations<double[]>::value, "So no array of doubles!");
|
||||
+static_assert(!has_unique_object_representations<double[][42]>::value, "So no array of doubles!");
|
||||
+
|
||||
+struct __attribute__((aligned(16))) WeirdAlignment {
|
||||
+ int i;
|
||||
+};
|
||||
+union __attribute__((aligned(16))) WeirdAlignmentUnion {
|
||||
+ int i;
|
||||
+};
|
||||
+static_assert(!has_unique_object_representations<WeirdAlignment>::value, "Alignment causes padding");
|
||||
+static_assert(!has_unique_object_representations<WeirdAlignmentUnion>::value, "Alignment causes padding");
|
||||
+static_assert(!has_unique_object_representations<WeirdAlignment[42]>::value, "Also no arrays that have padding");
|
||||
+
|
||||
+static_assert(!has_unique_object_representations<int(int)>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int) const>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int) volatile>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int) const volatile>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int) &>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int) const &>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int) volatile &>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int) const volatile &>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int) &&>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int) const &&>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int) volatile &&>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int) const volatile &&>::value, "Functions are not unique");
|
||||
+
|
||||
+static_assert(!has_unique_object_representations<int(int, ...)>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int, ...) const>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int, ...) volatile>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int, ...) const volatile>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int, ...) &>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int, ...) const &>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int, ...) volatile &>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int, ...) const volatile &>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int, ...) &&>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int, ...) const &&>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int, ...) volatile &&>::value, "Functions are not unique");
|
||||
+static_assert(!has_unique_object_representations<int(int, ...) const volatile &&>::value, "Functions are not unique");
|
||||
+
|
||||
+void foo(){
|
||||
+ static auto lambda = []() {};
|
||||
+ static_assert(!has_unique_object_representations<decltype(lambda)>::value, "Lambdas follow struct rules");
|
||||
+ int i;
|
||||
+ static auto lambda2 = [i]() {};
|
||||
+ static_assert(has_unique_object_representations<decltype(lambda2)>::value, "Lambdas follow struct rules");
|
||||
+}
|
||||
+
|
||||
+struct PaddedBitfield {
|
||||
+ char c : 6;
|
||||
+ char d : 1;
|
||||
+};
|
||||
+
|
||||
+struct UnPaddedBitfield {
|
||||
+ char c : 6;
|
||||
+ char d : 2;
|
||||
+};
|
||||
+
|
||||
+struct AlignedPaddedBitfield {
|
||||
+ char c : 6;
|
||||
+ __attribute__((aligned(1)))
|
||||
+ char d : 2;
|
||||
+};
|
||||
+
|
||||
+static_assert(!has_unique_object_representations<PaddedBitfield>::value, "Bitfield padding");
|
||||
+static_assert(has_unique_object_representations<UnPaddedBitfield>::value, "Bitfield padding");
|
||||
+static_assert(!has_unique_object_representations<AlignedPaddedBitfield>::value, "Bitfield padding");
|
||||
+
|
||||
+struct BoolBitfield {
|
||||
+ bool b : 8;
|
||||
+};
|
||||
+
|
||||
+static_assert(has_unique_object_representations<BoolBitfield>::value, "Bitfield bool");
|
||||
+
|
||||
+struct BoolBitfield2 {
|
||||
+ bool b : 16;
|
||||
+};
|
||||
+
|
||||
+static_assert(!has_unique_object_representations<BoolBitfield2>::value, "Bitfield bool");
|
||||
+
|
||||
+struct GreaterSizeBitfield {
|
||||
+ //expected-warning@+1 {{width of bit-field 'n'}}
|
||||
+ int n : 1024;
|
||||
+};
|
||||
+
|
||||
+static_assert(sizeof(GreaterSizeBitfield) == 128, "Bitfield Size");
|
||||
+static_assert(!has_unique_object_representations<GreaterSizeBitfield>::value, "Bitfield padding");
|
||||
+
|
||||
+struct StructWithRef {
|
||||
+ int &I;
|
||||
+};
|
||||
+
|
||||
+static_assert(has_unique_object_representations<StructWithRef>::value, "References are still unique");
|
||||
+
|
||||
+struct NotUniqueBecauseTailPadding {
|
||||
+ int &r;
|
||||
+ char a;
|
||||
+};
|
||||
+struct CanBeUniqueIfNoPadding : NotUniqueBecauseTailPadding {
|
||||
+ char b[7];
|
||||
+};
|
||||
+
|
||||
+static_assert(!has_unique_object_representations<NotUniqueBecauseTailPadding>::value,
|
||||
+ "non trivial");
|
||||
+// Can be unique on Itanium, since the is child class' data is 'folded' into the
|
||||
+// parent's tail padding.
|
||||
+static_assert(sizeof(CanBeUniqueIfNoPadding) != 16 ||
|
||||
+ has_unique_object_representations<CanBeUniqueIfNoPadding>::value,
|
||||
+ "inherit from std layout");
|
||||
+
|
||||
+namespace ErrorType {
|
||||
+ struct S; //expected-note{{forward declaration of 'ErrorType::S'}}
|
||||
+
|
||||
+ struct T {
|
||||
+ S t; //expected-error{{field has incomplete type 'ErrorType::S'}}
|
||||
+ };
|
||||
+ bool b = __has_unique_object_representations(T);
|
||||
+};
|
||||
--
|
||||
2.14.1
|
||||
|
@@ -1,122 +0,0 @@
|
||||
diff --git a/tools/clang/include/clang/Basic/TokenKinds.def b/tools/clang/include/clang/Basic/TokenKinds.def
|
||||
index 90ac33b9ea..67fea10788 100644
|
||||
--- a/tools/clang/include/clang/Basic/TokenKinds.def
|
||||
+++ b/tools/clang/include/clang/Basic/TokenKinds.def
|
||||
@@ -390,6 +390,7 @@ TYPE_TRAIT_2(__builtin_types_compatible_p, TypeCompatible, KEYNOCXX)
|
||||
KEYWORD(__builtin_va_arg , KEYALL)
|
||||
KEYWORD(__extension__ , KEYALL)
|
||||
KEYWORD(__float128 , KEYALL)
|
||||
+ALIAS("_Float128", __float128 , KEYNOCXX)
|
||||
KEYWORD(__imag , KEYALL)
|
||||
KEYWORD(__int128 , KEYALL)
|
||||
KEYWORD(__label__ , KEYALL)
|
||||
diff --git a/tools/clang/lib/Frontend/InitPreprocessor.cpp b/tools/clang/lib/Frontend/InitPreprocessor.cpp
|
||||
index 92d61369b4..8edc06fe93 100644
|
||||
--- a/tools/clang/lib/Frontend/InitPreprocessor.cpp
|
||||
+++ b/tools/clang/lib/Frontend/InitPreprocessor.cpp
|
||||
@@ -790,6 +790,10 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
|
||||
DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat(), "F");
|
||||
DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat(), "");
|
||||
DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat(), "L");
|
||||
+ if (TI.hasFloat128Type())
|
||||
+ // FIXME: Switch away from the non-standard "Q" when we can
|
||||
+ DefineFloatMacros(Builder, "FLT128", &TI.getFloat128Format(), "Q");
|
||||
+
|
||||
|
||||
// Define a __POINTER_WIDTH__ macro for stdint.h.
|
||||
Builder.defineMacro("__POINTER_WIDTH__",
|
||||
diff --git a/tools/clang/test/Preprocessor/cuda-types.cu b/tools/clang/test/Preprocessor/cuda-types.cu
|
||||
index 5f7b91655c..9e96f6a15e 100644
|
||||
--- a/tools/clang/test/Preprocessor/cuda-types.cu
|
||||
+++ b/tools/clang/test/Preprocessor/cuda-types.cu
|
||||
@@ -5,42 +5,44 @@
|
||||
// FIXME: We really should make __GCC_HAVE_SYNC_COMPARE_AND_SWAP identical on
|
||||
// host and device, but architecturally this is difficult at the moment.
|
||||
|
||||
+// RUN: mkdir -p %t
|
||||
+
|
||||
// RUN: %clang --cuda-host-only -nocudainc -target i386-unknown-linux-gnu -x cuda -E -dM -o - /dev/null \
|
||||
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
|
||||
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/i386-host-defines-filtered
|
||||
+// RUN: | grep -v '__FLT128\|__LDBL\|_LONG_DOUBLE' > %t/i386-host-defines-filtered
|
||||
// RUN: %clang --cuda-device-only -nocudainc -nocudalib -target i386-unknown-linux-gnu -x cuda -E -dM -o - /dev/null \
|
||||
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
|
||||
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/i386-device-defines-filtered
|
||||
-// RUN: diff %T/i386-host-defines-filtered %T/i386-device-defines-filtered
|
||||
+// RUN: | grep -v '__FLT128\|__LDBL\|_LONG_DOUBLE' > %t/i386-device-defines-filtered
|
||||
+// RUN: diff %t/i386-host-defines-filtered %t/i386-device-defines-filtered
|
||||
|
||||
// RUN: %clang --cuda-host-only -nocudainc -target x86_64-unknown-linux-gnu -x cuda -E -dM -o - /dev/null \
|
||||
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
|
||||
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/x86_64-host-defines-filtered
|
||||
+// RUN: | grep -v '__FLT128\|__LDBL\|_LONG_DOUBLE' > %t/x86_64-host-defines-filtered
|
||||
// RUN: %clang --cuda-device-only -nocudainc -nocudalib -target x86_64-unknown-linux-gnu -x cuda -E -dM -o - /dev/null \
|
||||
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
|
||||
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/x86_64-device-defines-filtered
|
||||
-// RUN: diff %T/x86_64-host-defines-filtered %T/x86_64-device-defines-filtered
|
||||
+// RUN: | grep -v '__FLT128\|__LDBL\|_LONG_DOUBLE' > %t/x86_64-device-defines-filtered
|
||||
+// RUN: diff %t/x86_64-host-defines-filtered %t/x86_64-device-defines-filtered
|
||||
|
||||
// RUN: %clang --cuda-host-only -nocudainc -target powerpc64-unknown-linux-gnu -x cuda -E -dM -o - /dev/null \
|
||||
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
|
||||
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/powerpc64-host-defines-filtered
|
||||
+// RUN: | grep -v '__FLT128\|__LDBL\|_LONG_DOUBLE' > %t/powerpc64-host-defines-filtered
|
||||
// RUN: %clang --cuda-device-only -nocudainc -nocudalib -target powerpc64-unknown-linux-gnu -x cuda -E -dM -o - /dev/null \
|
||||
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
|
||||
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/powerpc64-device-defines-filtered
|
||||
-// RUN: diff %T/powerpc64-host-defines-filtered %T/powerpc64-device-defines-filtered
|
||||
+// RUN: | grep -v '__FLT128\|__LDBL\|_LONG_DOUBLE' > %t/powerpc64-device-defines-filtered
|
||||
+// RUN: diff %t/powerpc64-host-defines-filtered %t/powerpc64-device-defines-filtered
|
||||
|
||||
// RUN: %clang --cuda-host-only -nocudainc -target i386-windows-msvc -x cuda -E -dM -o - /dev/null \
|
||||
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
|
||||
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/i386-msvc-host-defines-filtered
|
||||
+// RUN: | grep -v '__FLT128\|__LDBL\|_LONG_DOUBLE' > %t/i386-msvc-host-defines-filtered
|
||||
// RUN: %clang --cuda-device-only -nocudainc -nocudalib -target i386-windows-msvc -x cuda -E -dM -o - /dev/null \
|
||||
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
|
||||
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/i386-msvc-device-defines-filtered
|
||||
-// RUN: diff %T/i386-msvc-host-defines-filtered %T/i386-msvc-device-defines-filtered
|
||||
+// RUN: | grep -v '__FLT128\|__LDBL\|_LONG_DOUBLE' > %t/i386-msvc-device-defines-filtered
|
||||
+// RUN: diff %t/i386-msvc-host-defines-filtered %t/i386-msvc-device-defines-filtered
|
||||
|
||||
// RUN: %clang --cuda-host-only -nocudainc -target x86_64-windows-msvc -x cuda -E -dM -o - /dev/null \
|
||||
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
|
||||
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/x86_64-msvc-host-defines-filtered
|
||||
+// RUN: | grep -v '__FLT128\|__LDBL\|_LONG_DOUBLE' > %t/x86_64-msvc-host-defines-filtered
|
||||
// RUN: %clang --cuda-device-only -nocudainc -nocudalib -target x86_64-windows-msvc -x cuda -E -dM -o - /dev/null \
|
||||
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
|
||||
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/x86_64-msvc-device-defines-filtered
|
||||
-// RUN: diff %T/x86_64-msvc-host-defines-filtered %T/x86_64-msvc-device-defines-filtered
|
||||
+// RUN: | grep -v '__FLT128\|__LDBL\|_LONG_DOUBLE' > %t/x86_64-msvc-device-defines-filtered
|
||||
+// RUN: diff %t/x86_64-msvc-host-defines-filtered %t/x86_64-msvc-device-defines-filtered
|
||||
diff --git a/tools/clang/test/Sema/_Float128.c b/tools/clang/test/Sema/_Float128.c
|
||||
new file mode 100644
|
||||
index 0000000000..f0c3c6d555
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/Sema/_Float128.c
|
||||
@@ -0,0 +1,22 @@
|
||||
+// RUN: %clang_cc1 -verify %s
|
||||
+// RUN: %clang_cc1 -triple powerpc64-linux -verify %s
|
||||
+// RUN: %clang_cc1 -triple i686-windows-gnu -verify %s
|
||||
+// RUN: %clang_cc1 -triple x86_64-windows-gnu -verify %s
|
||||
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -verify %s
|
||||
+
|
||||
+#if defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__)
|
||||
+_Float128 f;
|
||||
+_Float128 tiny = __FLT128_EPSILON__;
|
||||
+int g(int x, _Float128 *y) {
|
||||
+ return x + *y;
|
||||
+}
|
||||
+
|
||||
+// expected-no-diagnostics
|
||||
+#else
|
||||
+_Float128 f; // expected-error {{__float128 is not supported on this target}}
|
||||
+float tiny = __FLT128_EPSILON__; // expected-error{{use of undeclared identifier}}
|
||||
+int g(int x, _Float128 *y) { // expected-error {{__float128 is not supported on this target}}
|
||||
+ return x + *y;
|
||||
+}
|
||||
+
|
||||
+#endif // defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__)
|
||||
--
|
||||
2.14.1
|
||||
|
129
dist/clang/patches/240_Link-clang-tools.patch
vendored
129
dist/clang/patches/240_Link-clang-tools.patch
vendored
@@ -1,129 +0,0 @@
|
||||
diff --git a/tools/clang/tools/driver/CMakeLists.txt b/tools/clang/tools/driver/CMakeLists.txt
|
||||
index 901b6d62e4..178e7a1882 100644
|
||||
--- a/tools/clang/tools/driver/CMakeLists.txt
|
||||
+++ b/tools/clang/tools/driver/CMakeLists.txt
|
||||
@@ -43,6 +43,9 @@ target_link_libraries(clang
|
||||
clangDriver
|
||||
clangFrontend
|
||||
clangFrontendTool
|
||||
+ clangTidyPlugin
|
||||
+ clangIncludeFixerPlugin
|
||||
+ clazyPlugin
|
||||
)
|
||||
|
||||
if(WIN32 AND NOT CYGWIN)
|
||||
diff --git a/tools/clang/tools/driver/driver.cpp b/tools/clang/tools/driver/driver.cpp
|
||||
index 9f37c428ff..475c5f84c0 100644
|
||||
--- a/tools/clang/tools/driver/driver.cpp
|
||||
+++ b/tools/clang/tools/driver/driver.cpp
|
||||
@@ -517,3 +517,18 @@ int main(int argc_, const char **argv_) {
|
||||
// failing command.
|
||||
return Res;
|
||||
}
|
||||
+
|
||||
+// This anchor is used to force the linker to link the clang-tidy plugin.
|
||||
+extern volatile int ClangTidyPluginAnchorSource;
|
||||
+static int LLVM_ATTRIBUTE_UNUSED ClangTidyPluginAnchorDestination =
|
||||
+ ClangTidyPluginAnchorSource;
|
||||
+
|
||||
+// This anchor is used to force the linker to link the clang-include-fixer
|
||||
+// plugin.
|
||||
+extern volatile int ClangIncludeFixerPluginAnchorSource;
|
||||
+static int LLVM_ATTRIBUTE_UNUSED ClangIncludeFixerPluginAnchorDestination =
|
||||
+ ClangIncludeFixerPluginAnchorSource;
|
||||
+
|
||||
+// This anchor is used to force the linker to link the clazy plugin.
|
||||
+extern volatile int ClazyPluginAnchorSource;
|
||||
+static int LLVM_ATTRIBUTE_UNUSED ClazyPluginAnchorDestination = ClazyPluginAnchorSource;
|
||||
diff --git a/tools/clang/tools/extra/clang-tidy/modernize/LoopConvertCheck.cpp b/tools/clang/tools/extra/clang-tidy/modernize/LoopConvertCheck.cpp
|
||||
index ac0bceb1..305bd78a 100644
|
||||
--- a/tools/clang/tools/extra/clang-tidy/modernize/LoopConvertCheck.cpp
|
||||
+++ b/tools/clang/tools/extra/clang-tidy/modernize/LoopConvertCheck.cpp
|
||||
@@ -44,9 +44,6 @@ static const char EndVarName[] = "endVar";
|
||||
static const char DerefByValueResultName[] = "derefByValueResult";
|
||||
static const char DerefByRefResultName[] = "derefByRefResult";
|
||||
|
||||
-// shared matchers
|
||||
-static const TypeMatcher AnyType = anything();
|
||||
-
|
||||
static const StatementMatcher IntegerComparisonMatcher =
|
||||
expr(ignoringParenImpCasts(
|
||||
declRefExpr(to(varDecl(hasType(isInteger())).bind(ConditionVarName)))));
|
||||
@@ -173,6 +170,8 @@ StatementMatcher makeIteratorLoopMatcher() {
|
||||
qualType(unless(hasCanonicalType(rValueReferenceType())))
|
||||
.bind(DerefByRefResultName)))))));
|
||||
|
||||
+ static const TypeMatcher AnyType = anything();
|
||||
+
|
||||
return forStmt(
|
||||
unless(isInTemplateInstantiation()),
|
||||
hasLoopInit(anyOf(declStmt(declCountIs(2),
|
||||
diff --git a/tools/clang/tools/extra/clang-tidy/plugin/CMakeLists.txt b/tools/clang/tools/extra/clang-tidy/plugin/CMakeLists.txt
|
||||
index 5c888327..832e2090 100644
|
||||
--- a/tools/clang/tools/extra/clang-tidy/plugin/CMakeLists.txt
|
||||
+++ b/tools/clang/tools/extra/clang-tidy/plugin/CMakeLists.txt
|
||||
@@ -10,9 +10,11 @@ add_clang_library(clangTidyPlugin
|
||||
clangTidy
|
||||
clangTidyAndroidModule
|
||||
clangTidyBoostModule
|
||||
+ clangTidyBugproneModule
|
||||
clangTidyCERTModule
|
||||
clangTidyCppCoreGuidelinesModule
|
||||
clangTidyGoogleModule
|
||||
+ clangTidyHICPPModule
|
||||
clangTidyLLVMModule
|
||||
clangTidyMiscModule
|
||||
clangTidyModernizeModule
|
||||
diff --git a/tools/clang/tools/extra/clang-tidy/plugin/ClangTidyPlugin.cpp b/tools/clang/tools/extra/clang-tidy/plugin/ClangTidyPlugin.cpp
|
||||
index 1e6346c2..7028c40c 100644
|
||||
--- a/tools/clang/tools/extra/clang-tidy/plugin/ClangTidyPlugin.cpp
|
||||
+++ b/tools/clang/tools/extra/clang-tidy/plugin/ClangTidyPlugin.cpp
|
||||
@@ -83,6 +83,16 @@ extern volatile int CERTModuleAnchorSource;
|
||||
static int LLVM_ATTRIBUTE_UNUSED CERTModuleAnchorDestination =
|
||||
CERTModuleAnchorSource;
|
||||
|
||||
+// This anchor is used to force the linker to link the BoostModule.
|
||||
+extern volatile int BoostModuleAnchorSource;
|
||||
+static int LLVM_ATTRIBUTE_UNUSED BoostModuleAnchorDestination =
|
||||
+ BoostModuleAnchorSource;
|
||||
+
|
||||
+// This anchor is used to force the linker to link the BugproneModule.
|
||||
+extern volatile int BugproneModuleAnchorSource;
|
||||
+static int LLVM_ATTRIBUTE_UNUSED BugproneModuleAnchorDestination =
|
||||
+ BugproneModuleAnchorSource;
|
||||
+
|
||||
// This anchor is used to force the linker to link the LLVMModule.
|
||||
extern volatile int LLVMModuleAnchorSource;
|
||||
static int LLVM_ATTRIBUTE_UNUSED LLVMModuleAnchorDestination =
|
||||
@@ -98,6 +108,11 @@ extern volatile int GoogleModuleAnchorSource;
|
||||
static int LLVM_ATTRIBUTE_UNUSED GoogleModuleAnchorDestination =
|
||||
GoogleModuleAnchorSource;
|
||||
|
||||
+// This anchor is used to force the linker to link the AndroidModule.
|
||||
+extern volatile int AndroidModuleAnchorSource;
|
||||
+static int LLVM_ATTRIBUTE_UNUSED AndroidModuleAnchorDestination =
|
||||
+ AndroidModuleAnchorSource;
|
||||
+
|
||||
// This anchor is used to force the linker to link the MiscModule.
|
||||
extern volatile int MiscModuleAnchorSource;
|
||||
static int LLVM_ATTRIBUTE_UNUSED MiscModuleAnchorDestination =
|
||||
@@ -111,7 +126,7 @@ static int LLVM_ATTRIBUTE_UNUSED ModernizeModuleAnchorDestination =
|
||||
// This anchor is used to force the linker to link the MPIModule.
|
||||
extern volatile int MPIModuleAnchorSource;
|
||||
static int LLVM_ATTRIBUTE_UNUSED MPIModuleAnchorDestination =
|
||||
- MPIModuleAnchorSource;
|
||||
+ MPIModuleAnchorSource;
|
||||
|
||||
// This anchor is used to force the linker to link the PerformanceModule.
|
||||
extern volatile int PerformanceModuleAnchorSource;
|
||||
@@ -123,5 +138,10 @@ extern volatile int ReadabilityModuleAnchorSource;
|
||||
static int LLVM_ATTRIBUTE_UNUSED ReadabilityModuleAnchorDestination =
|
||||
ReadabilityModuleAnchorSource;
|
||||
|
||||
+// This anchor is used to force the linker to link the HICPPModule.
|
||||
+extern volatile int HICPPModuleAnchorSource;
|
||||
+static int LLVM_ATTRIBUTE_UNUSED HICPPModuleAnchorDestination =
|
||||
+ HICPPModuleAnchorSource;
|
||||
+
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
149
dist/clang/patches/README.md
vendored
149
dist/clang/patches/README.md
vendored
@@ -1,149 +0,0 @@
|
||||
Extra patches to LLVM/Clang 5.0
|
||||
===============================
|
||||
|
||||
The patches in this directory are applied to LLVM/Clang with:
|
||||
|
||||
$ cd $LLVM_SOURCE_DIR
|
||||
$ git apply --whitespace=fix $QT_CREATOR_SOURCE/dist/clang/patches/*.patch
|
||||
|
||||
Backported changes
|
||||
------------------
|
||||
|
||||
##### 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.
|
||||
|
||||
##### 120_D41688_Fix-crash-on-code-completion-in-comment-in-included-file.patch
|
||||
|
||||
* <https://reviews.llvm.org/D41688>
|
||||
|
||||
[Lex] Fix crash on code completion in comment in included file.
|
||||
|
||||
##### 100_D40841_Fix-a-crash-on-C++17-AST-for-non-trivial-construction-into-a-trivial-brace-initialize.patch
|
||||
|
||||
* <https://reviews.llvm.org/D40841>
|
||||
|
||||
[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.
|
||||
|
||||
##### 220_Support-std-has_unique_object_represesentations.patch
|
||||
|
||||
* https://reviews.llvm.org/D39064 mplement __has_unique_object_representations
|
||||
* https://reviews.llvm.org/D39347 Fix __has_unique_object_representations implementation
|
||||
* (without review, git sha1 133cba2f9263f63f44b6b086a500f374bff13eee) Fix ICE when __has_unqiue_object_representations called with invalid decl
|
||||
* (without review, git cb61fc53dc997bca3bee98d898d3406d0acb221c) Revert unintended hunk from ICE-Change
|
||||
* https://reviews.llvm.org/D42863 Make __has_unique_object_representations reject empty union types.
|
||||
|
||||
Backport patches implementing std::has_unique_object_representations for
|
||||
parsing type_traits header of stdlibc++ 7.
|
||||
|
||||
|
||||
##### 230_D40673_Add-Float128-as-alias-to-__float128.patch
|
||||
|
||||
* https://reviews.llvm.org/D40673
|
||||
|
||||
Fixes parsing stdlib.h with -DGNU_SOURCE for GCC 7.2 (and maybe others).
|
||||
|
||||
Additional changes
|
||||
------------------
|
||||
|
||||
##### 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.
|
||||
|
||||
##### 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>
|
||||
|
||||
Builds Clazy as an LLVM part and forces link for Clazy plugin registry entry.
|
||||
|
||||
##### 200_D36390_Fix-overloaded-static-functions-in-SemaCodeComplete.patch
|
||||
|
||||
* <https://reviews.llvm.org/D36390>
|
||||
* <https://bugs.llvm.org/show_bug.cgi?id=33904>
|
||||
|
||||
Fix overloaded static functions in SemaCodeComplete
|
||||
|
||||
Happens when static function is accessed via the class variable.
|
||||
That leads to incorrect overloads number because the variable is considered as the first argument.
|
||||
|
||||
##### 210_D43453_Fix-overloaded-static-functions-for-templates.patch
|
||||
|
||||
* <https://reviews.llvm.org/D43453>
|
||||
|
||||
Fix overloaded static functions for templates
|
||||
|
||||
Apply almost the same fix as D36390 but for templates
|
@@ -1,7 +1,7 @@
|
||||
var Environment = require("qbs.Environment")
|
||||
var File = require("qbs.File")
|
||||
var FileInfo = require("qbs.FileInfo")
|
||||
var MinimumLLVMVersion = "5.0.0" // CLANG-UPGRADE-CHECK: Adapt minimum version numbers.
|
||||
var MinimumLLVMVersion = "6.0.0" // CLANG-UPGRADE-CHECK: Adapt minimum version numbers.
|
||||
var Process = require("qbs.Process")
|
||||
|
||||
function readOutput(executable, args)
|
||||
@@ -36,7 +36,7 @@ function llvmConfig(hostOS, qtcFunctions)
|
||||
{
|
||||
var llvmInstallDirFromEnv = Environment.getEnv("LLVM_INSTALL_DIR")
|
||||
var llvmConfigVariants = [
|
||||
"llvm-config", "llvm-config-5.0", "llvm-config-6.0", "llvm-config-7.0", "llvm-config-8.0",
|
||||
"llvm-config", "llvm-config-6.0", "llvm-config-7.0", "llvm-config-8.0", "llvm-config-9.0"
|
||||
];
|
||||
|
||||
// Prefer llvm-config* from LLVM_INSTALL_DIR
|
||||
|
@@ -56,8 +56,8 @@ Module {
|
||||
})
|
||||
property stringList llvmToolingCxxFlags: clangProbe.llvmToolingCxxFlags
|
||||
property bool toolingEnabled: !Environment.getEnv("QTC_NO_CLANG_LIBTOOLING")
|
||||
&& Utilities.versionCompare(llvmVersion, "5") > 0
|
||||
&& Utilities.versionCompare(llvmVersion, "6") < 0
|
||||
&& Utilities.versionCompare(llvmVersion, "6") > 0
|
||||
&& Utilities.versionCompare(llvmVersion, "7") < 0
|
||||
|
||||
validate: {
|
||||
if (!clangProbe.found) {
|
||||
|
@@ -65,7 +65,7 @@ Controls.TextField {
|
||||
}
|
||||
|
||||
ExtendedFunctionButton {
|
||||
x: 2
|
||||
x: 4
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
backendValue: lineEdit.backendValue
|
||||
visible: lineEdit.enabled && showExtendedFunctionButton
|
||||
@@ -127,7 +127,7 @@ Controls.TextField {
|
||||
|
||||
padding.top: 2
|
||||
padding.bottom: 2
|
||||
padding.left: 16
|
||||
padding.left: 18
|
||||
padding.right: lineEdit.showTranslateCheckBox ? 16 : 1
|
||||
background: Rectangle {
|
||||
implicitWidth: 100
|
||||
|
@@ -33,8 +33,10 @@ Controls.SpinBox {
|
||||
property color textColor: colorLogic.textColor
|
||||
property variant backendValue;
|
||||
|
||||
implicitWidth: 74
|
||||
|
||||
ExtendedFunctionButton {
|
||||
x: 2
|
||||
x: 4
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
backendValue: spinBox.backendValue
|
||||
visible: spinBox.enabled
|
||||
@@ -59,4 +61,5 @@ Controls.SpinBox {
|
||||
|
||||
style: CustomSpinBoxStyle {
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -191,8 +191,8 @@ TextEditor_CurrentLine_ScrollBarColor=ffffffff
|
||||
ProjectExplorer_TaskError_TextMarkColor=error
|
||||
ProjectExplorer_TaskWarn_TextMarkColor=warning
|
||||
|
||||
ClangCodeModel_Error_TextMarkColor=error
|
||||
ClangCodeModel_Warning_TextMarkColor=warning
|
||||
CodeModel_Error_TextMarkColor=error
|
||||
CodeModel_Warning_TextMarkColor=warning
|
||||
|
||||
PaletteWindow=normalBackground
|
||||
PaletteWindowText=text
|
||||
|
@@ -184,8 +184,8 @@ TextEditor_CurrentLine_ScrollBarColor=ff404040
|
||||
ProjectExplorer_TaskError_TextMarkColor=error
|
||||
ProjectExplorer_TaskWarn_TextMarkColor=warning
|
||||
|
||||
ClangCodeModel_Error_TextMarkColor=error
|
||||
ClangCodeModel_Warning_TextMarkColor=warning
|
||||
CodeModel_Error_TextMarkColor=error
|
||||
CodeModel_Warning_TextMarkColor=warning
|
||||
|
||||
QmlDesigner_BackgroundColor=qmlDesignerButtonColor
|
||||
QmlDesigner_HighlightColor=ff46a2da
|
||||
|
@@ -195,8 +195,8 @@ TextEditor_CurrentLine_ScrollBarColor=ffffffff
|
||||
ProjectExplorer_TaskError_TextMarkColor=error
|
||||
ProjectExplorer_TaskWarn_TextMarkColor=warning
|
||||
|
||||
ClangCodeModel_Error_TextMarkColor=error
|
||||
ClangCodeModel_Warning_TextMarkColor=warning
|
||||
CodeModel_Error_TextMarkColor=error
|
||||
CodeModel_Warning_TextMarkColor=warning
|
||||
|
||||
QmlDesigner_BackgroundColor=qmlDesignerButtonColor
|
||||
QmlDesigner_HighlightColor=ff3f91c4
|
||||
|
@@ -193,8 +193,8 @@ TextEditor_CurrentLine_ScrollBarColor=ff404040
|
||||
ProjectExplorer_TaskError_TextMarkColor=error
|
||||
ProjectExplorer_TaskWarn_TextMarkColor=warning
|
||||
|
||||
ClangCodeModel_Error_TextMarkColor=error
|
||||
ClangCodeModel_Warning_TextMarkColor=warning
|
||||
CodeModel_Error_TextMarkColor=error
|
||||
CodeModel_Warning_TextMarkColor=warning
|
||||
|
||||
QmlDesigner_BackgroundColor=qmlDesignerButtonColor
|
||||
QmlDesigner_HighlightColor=ff46a2da
|
||||
|
@@ -191,8 +191,8 @@ TextEditor_CurrentLine_ScrollBarColor=ff404040
|
||||
ProjectExplorer_TaskError_TextMarkColor=error
|
||||
ProjectExplorer_TaskWarn_TextMarkColor=warning
|
||||
|
||||
ClangCodeModel_Error_TextMarkColor=error
|
||||
ClangCodeModel_Warning_TextMarkColor=warning
|
||||
CodeModel_Error_TextMarkColor=error
|
||||
CodeModel_Warning_TextMarkColor=warning
|
||||
|
||||
QmlDesigner_BackgroundColor=qmlDesignerButtonColor
|
||||
QmlDesigner_HighlightColor=ff46a2da
|
||||
|
@@ -54,11 +54,18 @@ Item {
|
||||
}
|
||||
|
||||
function prettyPrintScale(amount) {
|
||||
var sign;
|
||||
if (amount < 0) {
|
||||
sign = "-";
|
||||
amount = -amount;
|
||||
} else {
|
||||
sign = "";
|
||||
}
|
||||
var unitOffset = 0;
|
||||
var unitAmount = 1;
|
||||
for (unitOffset = 0; amount > unitAmount * 1024; ++unitOffset, unitAmount *= 1024) {}
|
||||
var result = amount / unitAmount;
|
||||
return roundTo3Digits(result) + units[unitOffset];
|
||||
return sign + roundTo3Digits(result) + units[unitOffset];
|
||||
}
|
||||
|
||||
Connections {
|
||||
@@ -134,7 +141,7 @@ Item {
|
||||
anchors.bottomMargin: 2
|
||||
anchors.leftMargin: 2
|
||||
anchors.left: parent.left
|
||||
text: prettyPrintScale(index * row.stepVal)
|
||||
text: prettyPrintScale(row.minVal + index * row.stepVal)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
@@ -212,6 +212,11 @@ public:
|
||||
IconsCodeModelOverlayBackgroundColor,
|
||||
IconsCodeModelOverlayForegroundColor,
|
||||
|
||||
/* Code model text marks */
|
||||
|
||||
CodeModel_Error_TextMarkColor,
|
||||
CodeModel_Warning_TextMarkColor,
|
||||
|
||||
/* Output panes */
|
||||
|
||||
OutputPanes_DebugTextColor,
|
||||
@@ -287,10 +292,6 @@ public:
|
||||
ProjectExplorer_TaskError_TextMarkColor,
|
||||
ProjectExplorer_TaskWarn_TextMarkColor,
|
||||
|
||||
/* ClangCodeModel Plugin */
|
||||
ClangCodeModel_Error_TextMarkColor,
|
||||
ClangCodeModel_Warning_TextMarkColor,
|
||||
|
||||
/* QmlDesigner Plugin */
|
||||
QmlDesigner_BackgroundColor,
|
||||
QmlDesigner_HighlightColor,
|
||||
|
@@ -46,7 +46,6 @@ HEADERS += \
|
||||
android_global.h \
|
||||
androidbuildapkstep.h \
|
||||
androidbuildapkwidget.h \
|
||||
androidrunnable.h \
|
||||
androidtoolmanager.h \
|
||||
androidsdkmanager.h \
|
||||
androidavdmanager.h \
|
||||
@@ -94,7 +93,6 @@ SOURCES += \
|
||||
androidbuildapkstep.cpp \
|
||||
androidbuildapkwidget.cpp \
|
||||
androidqtsupport.cpp \
|
||||
androidrunnable.cpp \
|
||||
androidtoolmanager.cpp \
|
||||
androidsdkmanager.cpp \
|
||||
androidavdmanager.cpp \
|
||||
|
@@ -86,8 +86,6 @@ Project {
|
||||
"androidrunconfiguration.h",
|
||||
"androidruncontrol.cpp",
|
||||
"androidruncontrol.h",
|
||||
"androidrunnable.cpp",
|
||||
"androidrunnable.h",
|
||||
"androidrunner.cpp",
|
||||
"androidrunner.h",
|
||||
"androidrunnerworker.cpp",
|
||||
|
@@ -297,6 +297,7 @@ bool AndroidAvdManager::startAvdAsync(const QString &avdName) const
|
||||
return false;
|
||||
}
|
||||
QProcess *avdProcess = new QProcess();
|
||||
avdProcess->setReadChannelMode(QProcess::MergedChannels);
|
||||
QObject::connect(avdProcess,
|
||||
static_cast<void (QProcess::*)(int)>(&QProcess::finished),
|
||||
avdProcess,
|
||||
|
@@ -232,3 +232,4 @@ private:
|
||||
|
||||
} // namespace Android
|
||||
|
||||
Q_DECLARE_METATYPE(Android::AndroidDeviceInfo)
|
||||
|
@@ -51,9 +51,11 @@ const char ANDROID_SETTINGS_ID[] = "BB.Android Configurations";
|
||||
const char ANDROID_TOOLCHAIN_ID[] = "Qt4ProjectManager.ToolChain.Android";
|
||||
const char ANDROIDQT[] = "Qt4ProjectManager.QtVersion.Android";
|
||||
|
||||
const char ANDROID_AMSTARTARGS_ASPECT[] = "Android.AmStartArgs";
|
||||
const char ANDROID_PRESTARTSHELLCMDLIST_ASPECT[] = "Android.PreStartShellCmdList";
|
||||
const char ANDROID_POSTSTARTSHELLCMDLIST_ASPECT[] = "Android.PostStartShellCmdList";
|
||||
const char ANDROID_AMSTARTARGS[] = "Android.AmStartArgs";
|
||||
// Note: Can be set on RunConfiguration using an aspect and/or
|
||||
// the AndroidRunnerWorker using recordData()
|
||||
const char ANDROID_PRESTARTSHELLCMDLIST[] = "Android.PreStartShellCmdList";
|
||||
const char ANDROID_POSTFINISHSHELLCMDLIST[] = "Android.PostFinishShellCmdList";
|
||||
|
||||
const char ANDROID_DEVICE_TYPE[] = "Android.Device.Type";
|
||||
const char ANDROID_DEVICE_ID[] = "Android Device";
|
||||
@@ -69,6 +71,7 @@ const char ANDROID_DEPLOY_SETTINGS_FILE[] = "AndroidDeploySettingsFile";
|
||||
const char ANDROID_PACKAGE_SOURCE_DIR[] = "AndroidPackageSourceDir";
|
||||
const char ANDROID_EXTRA_LIBS[] = "AndroidExtraLibs";
|
||||
|
||||
const char ANDROID_PACKAGENAME[] = "Android.PackageName";
|
||||
const char ANDROID_PACKAGE_INSTALLATION_STEP_ID[] = "Qt4ProjectManager.AndroidPackageInstallationStep";
|
||||
|
||||
} // namespace Constants;
|
||||
|
@@ -111,20 +111,20 @@ AndroidRunConfiguration::AndroidRunConfiguration(Target *target, Core::Id id)
|
||||
: RunConfiguration(target, id)
|
||||
{
|
||||
auto amStartArgsAspect = new BaseStringAspect(this);
|
||||
amStartArgsAspect->setId(Constants::ANDROID_AMSTARTARGS_ASPECT);
|
||||
amStartArgsAspect->setId(Constants::ANDROID_AMSTARTARGS);
|
||||
amStartArgsAspect->setSettingsKey("Android.AmStartArgsKey");
|
||||
amStartArgsAspect->setLabelText(tr("Activity manager start options:"));
|
||||
amStartArgsAspect->setDisplayStyle(BaseStringAspect::LineEditDisplay);
|
||||
addExtraAspect(amStartArgsAspect);
|
||||
|
||||
auto preStartShellCmdAspect = new BaseStringListAspect(this);
|
||||
preStartShellCmdAspect->setId(Constants::ANDROID_PRESTARTSHELLCMDLIST_ASPECT);
|
||||
preStartShellCmdAspect->setId(Constants::ANDROID_PRESTARTSHELLCMDLIST);
|
||||
preStartShellCmdAspect->setSettingsKey("Android.PreStartShellCmdListKey");
|
||||
preStartShellCmdAspect->setLabel(tr("Shell commands to run on Android device before application launch."));
|
||||
addExtraAspect(preStartShellCmdAspect);
|
||||
|
||||
auto postStartShellCmdAspect = new BaseStringListAspect(this);
|
||||
postStartShellCmdAspect->setId(Constants::ANDROID_POSTSTARTSHELLCMDLIST_ASPECT);
|
||||
postStartShellCmdAspect->setId(Constants::ANDROID_POSTFINISHSHELLCMDLIST);
|
||||
postStartShellCmdAspect->setSettingsKey("Android.PostStartShellCmdListKey");
|
||||
postStartShellCmdAspect->setLabel(tr("Shell commands to run on Android device after application quits."));
|
||||
addExtraAspect(postStartShellCmdAspect);
|
||||
@@ -140,7 +140,7 @@ QWidget *AndroidRunConfiguration::createConfigurationWidget()
|
||||
auto widget = new QWidget;
|
||||
auto layout = new QFormLayout(widget);
|
||||
|
||||
extraAspect(Constants::ANDROID_AMSTARTARGS_ASPECT)->addToConfigurationLayout(layout);
|
||||
extraAspect(Constants::ANDROID_AMSTARTARGS)->addToConfigurationLayout(layout);
|
||||
|
||||
auto warningIconLabel = new QLabel;
|
||||
warningIconLabel->setPixmap(Utils::Icons::WARNING.pixmap());
|
||||
@@ -148,8 +148,8 @@ QWidget *AndroidRunConfiguration::createConfigurationWidget()
|
||||
auto warningLabel = new QLabel(tr("If the \"am start\" options conflict, the application might not start."));
|
||||
layout->addRow(warningIconLabel, warningLabel);
|
||||
|
||||
extraAspect(Constants::ANDROID_PRESTARTSHELLCMDLIST_ASPECT)->addToConfigurationLayout(layout);
|
||||
extraAspect(Constants::ANDROID_POSTSTARTSHELLCMDLIST_ASPECT)->addToConfigurationLayout(layout);
|
||||
extraAspect(Constants::ANDROID_PRESTARTSHELLCMDLIST)->addToConfigurationLayout(layout);
|
||||
extraAspect(Constants::ANDROID_POSTFINISHSHELLCMDLIST)->addToConfigurationLayout(layout);
|
||||
|
||||
auto wrapped = wrapWidget(widget);
|
||||
auto detailsWidget = qobject_cast<DetailsWidget *>(wrapped);
|
||||
|
@@ -1,37 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "androidrunnable.h"
|
||||
|
||||
namespace Android {
|
||||
|
||||
void *AndroidRunnable::staticTypeId = &AndroidRunnable::staticTypeId;
|
||||
|
||||
AndroidRunnable::AndroidRunnable()
|
||||
{
|
||||
qRegisterMetaType<AndroidRunnable>("AndroidRunnable");
|
||||
}
|
||||
|
||||
} // namespace Android
|
@@ -1,57 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "android_global.h"
|
||||
#include <projectexplorer/runnables.h>
|
||||
|
||||
namespace Android {
|
||||
|
||||
struct ANDROID_EXPORT AndroidRunnable
|
||||
{
|
||||
AndroidRunnable();
|
||||
QString packageName;
|
||||
QStringList beforeStartAdbCommands;
|
||||
QStringList afterFinishAdbCommands;
|
||||
|
||||
QString displayName() const { return packageName; }
|
||||
static void *staticTypeId;
|
||||
};
|
||||
|
||||
inline bool operator==(const AndroidRunnable &r1, const AndroidRunnable &r2)
|
||||
{
|
||||
return r1.packageName == r2.packageName
|
||||
&& r1.beforeStartAdbCommands == r2.beforeStartAdbCommands
|
||||
&& r1.afterFinishAdbCommands == r2.afterFinishAdbCommands;
|
||||
}
|
||||
|
||||
inline bool operator!=(const AndroidRunnable &r1, const AndroidRunnable &r2)
|
||||
{
|
||||
return !(r1 == r2);
|
||||
}
|
||||
|
||||
} // namespace Android
|
||||
Q_DECLARE_METATYPE(Android::AndroidRunnable)
|
@@ -120,7 +120,8 @@ AndroidRunner::AndroidRunner(RunControl *runControl,
|
||||
setDisplayName("AndroidRunner");
|
||||
static const int metaTypes[] = {
|
||||
qRegisterMetaType<QVector<QStringList> >("QVector<QStringList>"),
|
||||
qRegisterMetaType<Utils::Port>("Utils::Port")
|
||||
qRegisterMetaType<Utils::Port>("Utils::Port"),
|
||||
qRegisterMetaType<AndroidDeviceInfo>("Android::AndroidDeviceInfo")
|
||||
};
|
||||
Q_UNUSED(metaTypes);
|
||||
|
||||
@@ -128,21 +129,10 @@ AndroidRunner::AndroidRunner(RunControl *runControl,
|
||||
connect(&m_checkAVDTimer, &QTimer::timeout, this, &AndroidRunner::checkAVD);
|
||||
|
||||
QString intent = intentName.isEmpty() ? AndroidManager::intentName(m_target) : intentName;
|
||||
m_androidRunnable.packageName = intent.left(intent.indexOf('/'));
|
||||
|
||||
RunConfiguration *rc = runControl->runConfiguration();
|
||||
if (auto aspect = rc->extraAspect(Constants::ANDROID_PRESTARTSHELLCMDLIST_ASPECT)) {
|
||||
for (QString shellCmd : static_cast<BaseStringListAspect *>(aspect)->value())
|
||||
m_androidRunnable.beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd));
|
||||
}
|
||||
|
||||
if (auto aspect = rc->extraAspect(Constants::ANDROID_POSTSTARTSHELLCMDLIST_ASPECT)) {
|
||||
for (QString shellCmd : static_cast<BaseStringListAspect *>(aspect)->value())
|
||||
m_androidRunnable.afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd));
|
||||
}
|
||||
m_packageName = intent.left(intent.indexOf('/'));
|
||||
|
||||
const int apiLevel = AndroidManager::deviceApiLevel(m_target);
|
||||
m_worker.reset(new AndroidRunnerWorker(this, m_androidRunnable));
|
||||
m_worker.reset(new AndroidRunnerWorker(this, m_packageName));
|
||||
m_worker->setIntentName(intent);
|
||||
m_worker->setIsPreNougat(apiLevel <= 23);
|
||||
m_worker->setExtraAppParams(extraAppParams);
|
||||
@@ -193,7 +183,7 @@ void AndroidRunner::stop()
|
||||
{
|
||||
if (m_checkAVDTimer.isActive()) {
|
||||
m_checkAVDTimer.stop();
|
||||
appendMessage("\n\n" + tr("\"%1\" terminated.").arg(m_androidRunnable.packageName),
|
||||
appendMessage("\n\n" + tr("\"%1\" terminated.").arg(m_packageName),
|
||||
Utils::DebugFormat);
|
||||
return;
|
||||
}
|
||||
@@ -258,7 +248,7 @@ void AndroidRunner::launchAVD()
|
||||
emit androidDeviceInfoChanged(info);
|
||||
if (info.isValid()) {
|
||||
AndroidAvdManager avdManager;
|
||||
if (avdManager.findAvd(info.avdname).isEmpty()) {
|
||||
if (!info.avdname.isEmpty() && avdManager.findAvd(info.avdname).isEmpty()) {
|
||||
bool launched = avdManager.startAvdAsync(info.avdname);
|
||||
m_launchedAVDName = launched ? info.avdname:"";
|
||||
} else {
|
||||
|
@@ -26,7 +26,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidrunnable.h"
|
||||
|
||||
#include <projectexplorer/runconfiguration.h>
|
||||
#include <qmldebug/qmldebugcommandlinearguments.h>
|
||||
@@ -67,7 +66,7 @@ signals:
|
||||
void asyncStart();
|
||||
void asyncStop();
|
||||
void qmlServerReady(const QUrl &serverUrl);
|
||||
void androidDeviceInfoChanged(const AndroidDeviceInfo &deviceInfo);
|
||||
void androidDeviceInfoChanged(const Android::AndroidDeviceInfo &deviceInfo);
|
||||
void avdDetected();
|
||||
|
||||
private:
|
||||
@@ -80,7 +79,7 @@ private:
|
||||
void checkAVD();
|
||||
void launchAVD();
|
||||
|
||||
AndroidRunnable m_androidRunnable;
|
||||
QString m_packageName;
|
||||
QString m_launchedAVDName;
|
||||
QThread m_thread;
|
||||
QTimer m_checkAVDTimer;
|
||||
|
@@ -140,8 +140,8 @@ static void deleter(QProcess *p)
|
||||
p->deleteLater();
|
||||
}
|
||||
|
||||
AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const AndroidRunnable &runnable)
|
||||
: m_androidRunnable(runnable)
|
||||
AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packageName)
|
||||
: m_packageName(packageName)
|
||||
, m_adbLogcatProcess(nullptr, deleter)
|
||||
, m_psIsAlive(nullptr, deleter)
|
||||
, m_logCatRegExp(regExpLogcat)
|
||||
@@ -181,8 +181,22 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const AndroidRunnabl
|
||||
m_deviceSerialNumber = AndroidManager::deviceSerialNumber(target);
|
||||
m_apiLevel = AndroidManager::deviceApiLevel(target);
|
||||
|
||||
if (auto aspect = runConfig->extraAspect(Constants::ANDROID_AMSTARTARGS_ASPECT))
|
||||
if (auto aspect = runConfig->extraAspect(Constants::ANDROID_AMSTARTARGS))
|
||||
m_amStartExtraArgs = static_cast<BaseStringAspect *>(aspect)->value().split(' ');
|
||||
|
||||
if (auto aspect = runConfig->extraAspect(Constants::ANDROID_PRESTARTSHELLCMDLIST)) {
|
||||
for (const QString &shellCmd : static_cast<BaseStringListAspect *>(aspect)->value())
|
||||
m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd));
|
||||
}
|
||||
for (const QString &shellCmd : runner->recordedData(Constants::ANDROID_PRESTARTSHELLCMDLIST).toStringList())
|
||||
m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd));
|
||||
|
||||
if (auto aspect = runConfig->extraAspect(Constants::ANDROID_POSTFINISHSHELLCMDLIST)) {
|
||||
for (const QString &shellCmd : static_cast<BaseStringListAspect *>(aspect)->value())
|
||||
m_afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd));
|
||||
}
|
||||
for (const QString &shellCmd : runner->recordedData(Constants::ANDROID_POSTFINISHSHELLCMDLIST).toStringList())
|
||||
m_afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd));
|
||||
}
|
||||
|
||||
AndroidRunnerWorker::~AndroidRunnerWorker()
|
||||
@@ -229,7 +243,7 @@ bool AndroidRunnerWorker::runAdb(const QStringList &args, int timeoutS)
|
||||
void AndroidRunnerWorker::adbKill(qint64 pid)
|
||||
{
|
||||
runAdb({"shell", "kill", "-9", QString::number(pid)});
|
||||
runAdb({"shell", "run-as", m_androidRunnable.packageName, "kill", "-9", QString::number(pid)});
|
||||
runAdb({"shell", "run-as", m_packageName, "kill", "-9", QString::number(pid)});
|
||||
}
|
||||
|
||||
QStringList AndroidRunnerWorker::selector() const
|
||||
@@ -239,14 +253,14 @@ QStringList AndroidRunnerWorker::selector() const
|
||||
|
||||
void AndroidRunnerWorker::forceStop()
|
||||
{
|
||||
runAdb({"shell", "am", "force-stop", m_androidRunnable.packageName}, 30);
|
||||
runAdb({"shell", "am", "force-stop", m_packageName}, 30);
|
||||
|
||||
// try killing it via kill -9
|
||||
const QByteArray out = Utils::SynchronousProcess()
|
||||
.runBlocking(m_adb, selector() << QStringLiteral("shell") << pidScriptPreNougat)
|
||||
.allRawOutput();
|
||||
|
||||
qint64 pid = extractPID(out.simplified(), m_androidRunnable.packageName);
|
||||
qint64 pid = extractPID(out.simplified(), m_packageName);
|
||||
if (pid != -1) {
|
||||
adbKill(pid);
|
||||
}
|
||||
@@ -346,7 +360,7 @@ void AndroidRunnerWorker::asyncStartHelper()
|
||||
QTC_ASSERT(!m_adbLogcatProcess, /**/);
|
||||
m_adbLogcatProcess = std::move(logcatProcess);
|
||||
|
||||
for (const QString &entry: m_androidRunnable.beforeStartAdbCommands)
|
||||
for (const QString &entry : m_beforeStartAdbCommands)
|
||||
runAdb(entry.split(' ', QString::SkipEmptyParts));
|
||||
|
||||
QStringList args({"shell", "am", "start"});
|
||||
@@ -356,14 +370,14 @@ void AndroidRunnerWorker::asyncStartHelper()
|
||||
args << "-D";
|
||||
QString gdbServerSocket;
|
||||
// run-as <package-name> pwd fails on API 22 so route the pwd through shell.
|
||||
if (!runAdb({"shell", "run-as", m_androidRunnable.packageName, "/system/bin/sh", "-c", "pwd"})) {
|
||||
if (!runAdb({"shell", "run-as", m_packageName, "/system/bin/sh", "-c", "pwd"})) {
|
||||
emit remoteProcessFinished(tr("Failed to get process path. Reason: %1.").arg(m_lastRunAdbError));
|
||||
return;
|
||||
}
|
||||
gdbServerSocket = QString::fromUtf8(m_lastRunAdbRawOutput.trimmed()) + "/debug-socket";
|
||||
|
||||
QString gdbServerExecutable;
|
||||
if (!runAdb({"shell", "run-as", m_androidRunnable.packageName, "ls", "lib/"})) {
|
||||
if (!runAdb({"shell", "run-as", m_packageName, "ls", "lib/"})) {
|
||||
emit remoteProcessFinished(tr("Failed to get process path. Reason: %1.").arg(m_lastRunAdbError));
|
||||
return;
|
||||
}
|
||||
@@ -380,11 +394,11 @@ void AndroidRunnerWorker::asyncStartHelper()
|
||||
return;
|
||||
}
|
||||
|
||||
runAdb({"shell", "run-as", m_androidRunnable.packageName, "killall", gdbServerExecutable});
|
||||
runAdb({"shell", "run-as", m_androidRunnable.packageName, "rm", gdbServerSocket});
|
||||
runAdb({"shell", "run-as", m_packageName, "killall", gdbServerExecutable});
|
||||
runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket});
|
||||
std::unique_ptr<QProcess, Deleter> gdbServerProcess(new QProcess, deleter);
|
||||
gdbServerProcess->start(m_adb, selector() << "shell" << "run-as"
|
||||
<< m_androidRunnable.packageName << "lib/" + gdbServerExecutable
|
||||
<< m_packageName << "lib/" + gdbServerExecutable
|
||||
<< "--multi" << "+" + gdbServerSocket);
|
||||
if (!gdbServerProcess->waitForStarted()) {
|
||||
emit remoteProcessFinished(tr("Failed to start C++ debugger."));
|
||||
@@ -398,7 +412,7 @@ void AndroidRunnerWorker::asyncStartHelper()
|
||||
emit remoteProcessFinished(tr("Failed to forward C++ debugging ports. Reason: %1.").arg(m_lastRunAdbError));
|
||||
return;
|
||||
}
|
||||
m_androidRunnable.afterFinishAdbCommands.push_back(removeForward.join(' '));
|
||||
m_afterFinishAdbCommands.push_back(removeForward.join(' '));
|
||||
}
|
||||
|
||||
if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices) {
|
||||
@@ -411,7 +425,7 @@ void AndroidRunnerWorker::asyncStartHelper()
|
||||
.arg(m_lastRunAdbError));
|
||||
return;
|
||||
}
|
||||
m_androidRunnable.afterFinishAdbCommands.push_back(removeForward.join(' '));
|
||||
m_afterFinishAdbCommands.push_back(removeForward.join(' '));
|
||||
|
||||
args << "-e" << "qml_debug" << "true"
|
||||
<< "-e" << "qmljsdebugger"
|
||||
@@ -442,7 +456,7 @@ void AndroidRunnerWorker::asyncStart()
|
||||
asyncStartHelper();
|
||||
|
||||
m_pidFinder = Utils::onResultReady(Utils::runAsync(findProcessPID, m_adb, selector(),
|
||||
m_androidRunnable.packageName, m_isPreNougat),
|
||||
m_packageName, m_isPreNougat),
|
||||
bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1));
|
||||
}
|
||||
|
||||
@@ -467,7 +481,7 @@ void AndroidRunnerWorker::handleJdbWaiting()
|
||||
emit remoteProcessFinished(tr("Failed to forward jdb debugging ports. Reason: %1.").arg(m_lastRunAdbError));
|
||||
return;
|
||||
}
|
||||
m_androidRunnable.afterFinishAdbCommands.push_back(removeForward.join(' '));
|
||||
m_afterFinishAdbCommands.push_back(removeForward.join(' '));
|
||||
|
||||
auto jdbPath = AndroidConfigurations::currentConfig().openJDKLocation().appendPath("bin");
|
||||
if (Utils::HostOsInfo::isWindowsHost())
|
||||
@@ -527,7 +541,7 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
|
||||
m_processPID = pid;
|
||||
if (pid == -1) {
|
||||
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.")
|
||||
.arg(m_androidRunnable.packageName));
|
||||
.arg(m_packageName));
|
||||
// App died/killed. Reset log, monitor, jdb & gdb processes.
|
||||
m_adbLogcatProcess.reset();
|
||||
m_psIsAlive.reset();
|
||||
@@ -535,7 +549,7 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
|
||||
m_gdbServerProcess.reset();
|
||||
|
||||
// Run adb commands after application quit.
|
||||
for (const QString &entry: m_androidRunnable.afterFinishAdbCommands)
|
||||
for (const QString &entry: m_afterFinishAdbCommands)
|
||||
runAdb(entry.split(' ', QString::SkipEmptyParts));
|
||||
} else {
|
||||
// In debugging cases this will be funneled to the engine to actually start
|
||||
|
@@ -26,12 +26,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <projectexplorer/runconfiguration.h>
|
||||
|
||||
#include <qmldebug/qmldebugcommandlinearguments.h>
|
||||
|
||||
#include <QFuture>
|
||||
|
||||
#include "androidrunnable.h"
|
||||
|
||||
namespace Android {
|
||||
|
||||
class AndroidDeviceInfo;
|
||||
@@ -44,7 +44,7 @@ class AndroidRunnerWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AndroidRunnerWorker(ProjectExplorer::RunWorker *runner, const AndroidRunnable &runnable);
|
||||
AndroidRunnerWorker(ProjectExplorer::RunWorker *runner, const QString &packageName);
|
||||
~AndroidRunnerWorker() override;
|
||||
bool adbShellAmNeedsQuotes();
|
||||
bool runAdb(const QStringList &args, int timeoutS = 10);
|
||||
@@ -85,8 +85,10 @@ protected:
|
||||
|
||||
// Create the processes and timer in the worker thread, for correct thread affinity
|
||||
bool m_isPreNougat = false;
|
||||
AndroidRunnable m_androidRunnable;
|
||||
QString m_packageName;
|
||||
QString m_intentName;
|
||||
QStringList m_beforeStartAdbCommands;
|
||||
QStringList m_afterFinishAdbCommands;
|
||||
QString m_adb;
|
||||
QStringList m_amStartExtraArgs;
|
||||
qint64 m_processPID = -1;
|
||||
|
@@ -48,7 +48,6 @@
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/outputformat.h>
|
||||
#include <utils/qtcprocess.h>
|
||||
#include <utils/runextensions.h>
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
@@ -56,8 +55,9 @@
|
||||
#include <QFuture>
|
||||
#include <QFutureInterface>
|
||||
#include <QLabel>
|
||||
#include <QProcess>
|
||||
#include <QPushButton>
|
||||
#include <QTime>
|
||||
#include <QTimer>
|
||||
|
||||
#include <debugger/debuggerkitinformation.h>
|
||||
#include <debugger/debuggerruncontrol.h>
|
||||
@@ -88,9 +88,9 @@ TestRunner::TestRunner(QObject *parent) :
|
||||
&m_futureWatcher, &QFutureWatcher<TestResultPtr>::cancel);
|
||||
connect(&m_futureWatcher, &QFutureWatcher<TestResultPtr>::canceled,
|
||||
this, [this]() {
|
||||
cancelCurrent(UserCanceled);
|
||||
emit testResultReady(TestResultPtr(new FaultyTestResult(
|
||||
Result::MessageFatal, tr("Test run canceled by user."))));
|
||||
m_executingTests = false; // avoid being stuck if finished() signal won't get emitted
|
||||
});
|
||||
}
|
||||
|
||||
@@ -103,13 +103,15 @@ TestRunner::~TestRunner()
|
||||
|
||||
void TestRunner::setSelectedTests(const QList<TestConfiguration *> &selected)
|
||||
{
|
||||
QTC_ASSERT(!m_executingTests, return);
|
||||
qDeleteAll(m_selectedTests);
|
||||
m_selectedTests.clear();
|
||||
m_selectedTests = selected;
|
||||
m_selectedTests.append(selected);
|
||||
}
|
||||
|
||||
void TestRunner::runTest(TestRunMode mode, const TestTreeItem *item)
|
||||
{
|
||||
QTC_ASSERT(!m_executingTests, return);
|
||||
TestConfiguration *configuration = item->asConfiguration(mode);
|
||||
|
||||
if (configuration) {
|
||||
@@ -118,15 +120,16 @@ void TestRunner::runTest(TestRunMode mode, const TestTreeItem *item)
|
||||
}
|
||||
}
|
||||
|
||||
static QString processInformation(const QProcess &proc)
|
||||
static QString processInformation(const QProcess *proc)
|
||||
{
|
||||
QString information("\nCommand line: " + proc.program() + ' ' + proc.arguments().join(' '));
|
||||
QTC_ASSERT(proc, return QString());
|
||||
QString information("\nCommand line: " + proc->program() + ' ' + proc->arguments().join(' '));
|
||||
QStringList important = { "PATH" };
|
||||
if (Utils::HostOsInfo::isLinuxHost())
|
||||
important.append("LD_LIBRARY_PATH");
|
||||
else if (Utils::HostOsInfo::isMacHost())
|
||||
important.append({ "DYLD_LIBRARY_PATH", "DYLD_FRAMEWORK_PATH" });
|
||||
const QProcessEnvironment &environment = proc.processEnvironment();
|
||||
const QProcessEnvironment &environment = proc->processEnvironment();
|
||||
for (const QString &var : important)
|
||||
information.append('\n' + var + ": " + environment.value(var));
|
||||
return information;
|
||||
@@ -142,133 +145,131 @@ static QString rcInfo(const TestConfiguration * const config)
|
||||
|
||||
static QString constructOmittedDetailsString(const QStringList &omitted)
|
||||
{
|
||||
QString details = TestRunner::tr("Omitted the following arguments specified on the run "
|
||||
"configuration page for \"%1\":");
|
||||
for (const QString &arg : omitted)
|
||||
details += "\n" + arg;
|
||||
return details;
|
||||
return TestRunner::tr("Omitted the following arguments specified on the run "
|
||||
"configuration page for \"%1\":") + '\n' + omitted.join('\n');
|
||||
}
|
||||
|
||||
static void performTestRun(QFutureInterface<TestResultPtr> &futureInterface,
|
||||
const QList<TestConfiguration *> selectedTests,
|
||||
const TestSettings &settings)
|
||||
void TestRunner::scheduleNext()
|
||||
{
|
||||
const int timeout = settings.timeout;
|
||||
const bool omitRunConfigWarnings = settings.omitRunConfigWarn;
|
||||
QEventLoop eventLoop;
|
||||
int testCaseCount = 0;
|
||||
for (TestConfiguration *config : selectedTests) {
|
||||
config->completeTestInformation(TestRunMode::Run);
|
||||
if (config->project()) {
|
||||
testCaseCount += config->testCaseCount();
|
||||
if (!omitRunConfigWarnings && config->isGuessed()) {
|
||||
QString message = TestRunner::tr(
|
||||
"Project's run configuration was guessed for \"%1\".\n"
|
||||
"This might cause trouble during execution.\n"
|
||||
"(guessed from \"%2\")");
|
||||
message = message.arg(config->displayName()).arg(config->runConfigDisplayName());
|
||||
futureInterface.reportResult(
|
||||
TestResultPtr(new FaultyTestResult(Result::MessageWarn, message)));
|
||||
}
|
||||
} else {
|
||||
futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageWarn,
|
||||
TestRunner::tr("Project is null for \"%1\". Removing from test run.\n"
|
||||
"Check the test environment.").arg(config->displayName()))));
|
||||
}
|
||||
}
|
||||
QTC_ASSERT(!m_selectedTests.isEmpty(), onFinished(); return);
|
||||
QTC_ASSERT(!m_currentConfig && !m_currentProcess, resetInternalPointers());
|
||||
QTC_ASSERT(m_fakeFutureInterface, onFinished(); return);
|
||||
|
||||
QProcess testProcess;
|
||||
testProcess.setReadChannel(QProcess::StandardOutput);
|
||||
m_currentConfig = m_selectedTests.dequeue();
|
||||
|
||||
futureInterface.setProgressRange(0, testCaseCount);
|
||||
futureInterface.setProgressValue(0);
|
||||
|
||||
for (const TestConfiguration *testConfiguration : selectedTests) {
|
||||
QString commandFilePath = testConfiguration->executableFilePath();
|
||||
QString commandFilePath = m_currentConfig->executableFilePath();
|
||||
if (commandFilePath.isEmpty()) {
|
||||
futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
|
||||
TestRunner::tr("Executable path is empty. (%1)")
|
||||
.arg(testConfiguration->displayName()))));
|
||||
continue;
|
||||
}
|
||||
testProcess.setProgram(commandFilePath);
|
||||
|
||||
QScopedPointer<TestOutputReader> outputReader;
|
||||
outputReader.reset(testConfiguration->outputReader(futureInterface, &testProcess));
|
||||
QTC_ASSERT(outputReader, continue);
|
||||
TestRunner::connect(outputReader.data(), &TestOutputReader::newOutputAvailable,
|
||||
TestResultsPane::instance(), &TestResultsPane::addOutput);
|
||||
if (futureInterface.isCanceled())
|
||||
break;
|
||||
|
||||
if (!testConfiguration->project())
|
||||
continue;
|
||||
|
||||
QStringList omitted;
|
||||
testProcess.setArguments(testConfiguration->argumentsForTestRunner(&omitted));
|
||||
if (!omitted.isEmpty()) {
|
||||
const QString &details = constructOmittedDetailsString(omitted);
|
||||
futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageWarn,
|
||||
details.arg(testConfiguration->displayName()))));
|
||||
}
|
||||
testProcess.setWorkingDirectory(testConfiguration->workingDirectory());
|
||||
QProcessEnvironment environment = testConfiguration->environment().toProcessEnvironment();
|
||||
if (Utils::HostOsInfo::isWindowsHost())
|
||||
environment.insert("QT_LOGGING_TO_CONSOLE", "1");
|
||||
testProcess.setProcessEnvironment(environment);
|
||||
testProcess.start();
|
||||
|
||||
bool ok = testProcess.waitForStarted();
|
||||
QTime executionTimer;
|
||||
executionTimer.start();
|
||||
bool canceledByTimeout = false;
|
||||
if (ok) {
|
||||
while (testProcess.state() == QProcess::Running) {
|
||||
if (executionTimer.elapsed() >= timeout) {
|
||||
canceledByTimeout = true;
|
||||
break;
|
||||
}
|
||||
if (futureInterface.isCanceled()) {
|
||||
testProcess.kill();
|
||||
testProcess.waitForFinished();
|
||||
emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
|
||||
tr("Executable path is empty. (%1)").arg(m_currentConfig->displayName()))));
|
||||
delete m_currentConfig;
|
||||
m_currentConfig = nullptr;
|
||||
if (m_selectedTests.isEmpty())
|
||||
onFinished();
|
||||
else
|
||||
onProcessFinished();
|
||||
return;
|
||||
}
|
||||
eventLoop.processEvents();
|
||||
if (!m_currentConfig->project())
|
||||
onProcessFinished();
|
||||
|
||||
m_currentProcess = new QProcess;
|
||||
m_currentProcess->setReadChannel(QProcess::StandardOutput);
|
||||
m_currentProcess->setProgram(commandFilePath);
|
||||
|
||||
QTC_ASSERT(!m_currentOutputReader, delete m_currentOutputReader);
|
||||
m_currentOutputReader = m_currentConfig->outputReader(*m_fakeFutureInterface, m_currentProcess);
|
||||
QTC_ASSERT(m_currentOutputReader, onProcessFinished();return);
|
||||
|
||||
connect(m_currentOutputReader, &TestOutputReader::newOutputAvailable,
|
||||
TestResultsPane::instance(), &TestResultsPane::addOutput);
|
||||
|
||||
|
||||
QStringList omitted;
|
||||
m_currentProcess->setArguments(m_currentConfig->argumentsForTestRunner(&omitted));
|
||||
if (!omitted.isEmpty()) {
|
||||
const QString &details = constructOmittedDetailsString(omitted);
|
||||
emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn,
|
||||
details.arg(m_currentConfig->displayName()))));
|
||||
}
|
||||
} else {
|
||||
futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
|
||||
TestRunner::tr("Failed to start test for project \"%1\".")
|
||||
.arg(testConfiguration->displayName()) + processInformation(testProcess)
|
||||
+ rcInfo(testConfiguration))));
|
||||
m_currentProcess->setWorkingDirectory(m_currentConfig->workingDirectory());
|
||||
QProcessEnvironment environment = m_currentConfig->environment().toProcessEnvironment();
|
||||
if (Utils::HostOsInfo::isWindowsHost())
|
||||
environment.insert("QT_LOGGING_TO_CONSOLE", "1");
|
||||
const int timeout = AutotestPlugin::settings()->timeout;
|
||||
if (timeout > 5 * 60 * 1000) // Qt5.5 introduced hard limit, Qt5.6.1 added env var to raise this
|
||||
environment.insert("QTEST_FUNCTION_TIMEOUT", QString::number(timeout));
|
||||
m_currentProcess->setProcessEnvironment(environment);
|
||||
|
||||
connect(m_currentProcess,
|
||||
static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
||||
this, &TestRunner::onProcessFinished);
|
||||
QTimer::singleShot(timeout, m_currentProcess, [this]() { cancelCurrent(Timeout); });
|
||||
|
||||
m_currentProcess->start();
|
||||
if (!m_currentProcess->waitForStarted()) {
|
||||
emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
|
||||
tr("Failed to start test for project \"%1\".").arg(m_currentConfig->displayName())
|
||||
+ processInformation(m_currentProcess) + rcInfo(m_currentConfig))));
|
||||
}
|
||||
}
|
||||
|
||||
void TestRunner::cancelCurrent(TestRunner::CancelReason reason)
|
||||
{
|
||||
if (reason == UserCanceled) {
|
||||
if (!m_fakeFutureInterface->isCanceled()) // depends on using the button / progress bar
|
||||
m_fakeFutureInterface->reportCanceled();
|
||||
}
|
||||
if (m_currentProcess && m_currentProcess->state() != QProcess::NotRunning) {
|
||||
m_currentProcess->kill();
|
||||
m_currentProcess->waitForFinished();
|
||||
}
|
||||
if (reason == Timeout) {
|
||||
emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
|
||||
tr("Test case canceled due to timeout.\nMaybe raise the timeout?"))));
|
||||
}
|
||||
}
|
||||
|
||||
void TestRunner::onProcessFinished()
|
||||
{
|
||||
m_fakeFutureInterface->setProgressValue(m_fakeFutureInterface->progressValue()
|
||||
+ m_currentConfig->testCaseCount());
|
||||
if (!m_fakeFutureInterface->isCanceled()) {
|
||||
if (m_currentProcess->exitStatus() == QProcess::CrashExit) {
|
||||
m_currentOutputReader->reportCrash();
|
||||
emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
|
||||
tr("Test for project \"%1\" crashed.").arg(m_currentConfig->displayName())
|
||||
+ processInformation(m_currentProcess) + rcInfo(m_currentConfig))));
|
||||
} else if (!m_currentOutputReader->hadValidOutput()) {
|
||||
emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
|
||||
tr("Test for project \"%1\" did not produce any expected output.")
|
||||
.arg(m_currentConfig->displayName()) + processInformation(m_currentProcess)
|
||||
+ rcInfo(m_currentConfig))));
|
||||
}
|
||||
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)
|
||||
+ rcInfo(testConfiguration))));
|
||||
} else if (!outputReader->hadValidOutput()) {
|
||||
futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
|
||||
TestRunner::tr("Test for project \"%1\" did not produce any expected output.")
|
||||
.arg(testConfiguration->displayName()) + processInformation(testProcess)
|
||||
+ rcInfo(testConfiguration))));
|
||||
}
|
||||
|
||||
if (canceledByTimeout) {
|
||||
if (testProcess.state() != QProcess::NotRunning) {
|
||||
testProcess.kill();
|
||||
testProcess.waitForFinished();
|
||||
resetInternalPointers();
|
||||
|
||||
if (!m_selectedTests.isEmpty() && !m_fakeFutureInterface->isCanceled()) {
|
||||
scheduleNext();
|
||||
} else {
|
||||
m_fakeFutureInterface->reportFinished();
|
||||
onFinished();
|
||||
}
|
||||
futureInterface.reportResult(TestResultPtr(
|
||||
new FaultyTestResult(Result::MessageFatal, TestRunner::tr(
|
||||
"Test case canceled due to timeout.\nMaybe raise the timeout?"))));
|
||||
}
|
||||
}
|
||||
futureInterface.setProgressValue(testCaseCount);
|
||||
}
|
||||
|
||||
void TestRunner::resetInternalPointers()
|
||||
{
|
||||
delete m_currentOutputReader;
|
||||
delete m_currentProcess;
|
||||
delete m_currentConfig;
|
||||
m_currentOutputReader = nullptr;
|
||||
m_currentProcess = nullptr;
|
||||
m_currentConfig = nullptr;
|
||||
}
|
||||
|
||||
void TestRunner::prepareToRunTests(TestRunMode mode)
|
||||
{
|
||||
QTC_ASSERT(!m_executingTests, return);
|
||||
m_runMode = mode;
|
||||
ProjectExplorer::Internal::ProjectExplorerSettings projectExplorerSettings =
|
||||
ProjectExplorer::ProjectExplorerPlugin::projectExplorerSettings();
|
||||
@@ -358,6 +359,32 @@ static ProjectExplorer::RunConfiguration *getRunConfiguration(const QString &dia
|
||||
return runConfig;
|
||||
}
|
||||
|
||||
int TestRunner::precheckTestConfigurations()
|
||||
{
|
||||
const bool omitWarnings = AutotestPlugin::settings()->omitRunConfigWarn;
|
||||
int testCaseCount = 0;
|
||||
for (TestConfiguration *config : m_selectedTests) {
|
||||
config->completeTestInformation(TestRunMode::Run);
|
||||
if (config->project()) {
|
||||
testCaseCount += config->testCaseCount();
|
||||
if (!omitWarnings && config->isGuessed()) {
|
||||
QString message = tr(
|
||||
"Project's run configuration was guessed for \"%1\".\n"
|
||||
"This might cause trouble during execution.\n"
|
||||
"(guessed from \"%2\")");
|
||||
message = message.arg(config->displayName()).arg(config->runConfigDisplayName());
|
||||
emit testResultReady(
|
||||
TestResultPtr(new FaultyTestResult(Result::MessageWarn, message)));
|
||||
}
|
||||
} else {
|
||||
emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn,
|
||||
tr("Project is null for \"%1\". Removing from test run.\n"
|
||||
"Check the test environment.").arg(config->displayName()))));
|
||||
}
|
||||
}
|
||||
return testCaseCount;
|
||||
}
|
||||
|
||||
void TestRunner::runTests()
|
||||
{
|
||||
QList<TestConfiguration *> toBeRemoved;
|
||||
@@ -381,10 +408,17 @@ void TestRunner::runTests()
|
||||
return;
|
||||
}
|
||||
|
||||
QFuture<TestResultPtr> future = Utils::runAsync(&performTestRun, m_selectedTests,
|
||||
*AutotestPlugin::settings());
|
||||
int testCaseCount = precheckTestConfigurations();
|
||||
|
||||
// Fake future interface - destruction will be handled by QFuture/QFutureWatcher
|
||||
m_fakeFutureInterface = new QFutureInterface<TestResultPtr>(QFutureInterfaceBase::Running);
|
||||
QFuture<TestResultPtr> future = m_fakeFutureInterface->future();
|
||||
m_fakeFutureInterface->setProgressRange(0, testCaseCount);
|
||||
m_fakeFutureInterface->setProgressValue(0);
|
||||
m_futureWatcher.setFuture(future);
|
||||
|
||||
Core::ProgressManager::addTask(future, tr("Running Tests"), Autotest::Constants::TASK_INDEX);
|
||||
scheduleNext();
|
||||
}
|
||||
|
||||
static void processOutput(TestOutputReader *outputreader, const QString &msg,
|
||||
@@ -552,6 +586,11 @@ void TestRunner::buildFinished(bool success)
|
||||
|
||||
void TestRunner::onFinished()
|
||||
{
|
||||
// if we've been canceled and we still have test configurations queued just throw them away
|
||||
qDeleteAll(m_selectedTests);
|
||||
m_selectedTests.clear();
|
||||
|
||||
m_fakeFutureInterface = nullptr;
|
||||
m_executingTests = false;
|
||||
emit testRunFinished();
|
||||
}
|
||||
|
@@ -31,12 +31,13 @@
|
||||
#include <QDialog>
|
||||
#include <QFutureWatcher>
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
#include <QQueue>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QComboBox;
|
||||
class QDialogButtonBox;
|
||||
class QLabel;
|
||||
class QProcess;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace ProjectExplorer {
|
||||
@@ -51,6 +52,8 @@ class TestRunner : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum CancelReason { UserCanceled, Timeout };
|
||||
|
||||
static TestRunner* instance();
|
||||
~TestRunner();
|
||||
|
||||
@@ -71,14 +74,24 @@ private:
|
||||
void buildFinished(bool success);
|
||||
void onFinished();
|
||||
|
||||
int precheckTestConfigurations();
|
||||
void scheduleNext();
|
||||
void cancelCurrent(CancelReason reason);
|
||||
void onProcessFinished();
|
||||
void resetInternalPointers();
|
||||
|
||||
void runTests();
|
||||
void debugTests();
|
||||
void runOrDebugTests();
|
||||
explicit TestRunner(QObject *parent = 0);
|
||||
|
||||
QFutureWatcher<TestResultPtr> m_futureWatcher;
|
||||
QList<TestConfiguration *> m_selectedTests;
|
||||
bool m_executingTests;
|
||||
QFutureInterface<TestResultPtr> *m_fakeFutureInterface = nullptr;
|
||||
QQueue<TestConfiguration *> m_selectedTests;
|
||||
bool m_executingTests = false;
|
||||
TestConfiguration *m_currentConfig = nullptr;
|
||||
QProcess *m_currentProcess = nullptr;
|
||||
TestOutputReader *m_currentOutputReader = nullptr;
|
||||
TestRunMode m_runMode = TestRunMode::Run;
|
||||
|
||||
// temporarily used if building before running is necessary
|
||||
|
@@ -83,8 +83,8 @@ ClangTextMark::ClangTextMark(const FileName &fileName,
|
||||
updateIcon();
|
||||
if (fullVisualization) {
|
||||
setLineAnnotation(Utils::diagnosticCategoryPrefixRemoved(diagnostic.text.toString()));
|
||||
setColor(warning ? ::Utils::Theme::ClangCodeModel_Warning_TextMarkColor
|
||||
: ::Utils::Theme::ClangCodeModel_Error_TextMarkColor);
|
||||
setColor(warning ? ::Utils::Theme::CodeModel_Warning_TextMarkColor
|
||||
: ::Utils::Theme::CodeModel_Error_TextMarkColor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -161,6 +161,10 @@ ClangTidyClazyTool::ClangTidyClazyTool()
|
||||
// Apply fixits button
|
||||
m_applyFixitsButton = new QToolButton;
|
||||
m_applyFixitsButton->setText(tr("Apply Fixits"));
|
||||
m_applyFixitsButton->setEnabled(false);
|
||||
connect(m_diagnosticModel,
|
||||
&ClangToolsDiagnosticModel::fixItsToApplyCountChanged,
|
||||
[this](int c) { m_applyFixitsButton->setEnabled(c); });
|
||||
connect(m_applyFixitsButton, &QToolButton::clicked, [this]() {
|
||||
QVector<Diagnostic> diagnosticsWithFixits;
|
||||
|
||||
|
@@ -6,6 +6,7 @@ QtcPlugin {
|
||||
|
||||
Depends { name: "Debugger" }
|
||||
Depends { name: "Core" }
|
||||
Depends { name: "TextEditor" }
|
||||
Depends { name: "CppTools" }
|
||||
Depends { name: "ExtensionSystem" }
|
||||
Depends { name: "ProjectExplorer" }
|
||||
|
@@ -34,7 +34,6 @@
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <cmath>
|
||||
@@ -61,8 +60,13 @@ ClangToolsDiagnosticModel::ClangToolsDiagnosticModel(QObject *parent)
|
||||
|
||||
void ClangToolsDiagnosticModel::addDiagnostics(const QList<Diagnostic> &diagnostics)
|
||||
{
|
||||
foreach (const Diagnostic &d, diagnostics)
|
||||
rootItem()->appendChild(new DiagnosticItem(d));
|
||||
const auto onFixItChanged = [this](bool checked){
|
||||
m_fixItsToApplyCount += checked ? +1 : -1;
|
||||
emit fixItsToApplyCountChanged(m_fixItsToApplyCount);
|
||||
};
|
||||
|
||||
for (const Diagnostic &d : diagnostics)
|
||||
rootItem()->appendChild(new DiagnosticItem(d, onFixItChanged));
|
||||
}
|
||||
|
||||
QList<Diagnostic> ClangToolsDiagnosticModel::diagnostics() const
|
||||
@@ -199,7 +203,9 @@ static QString fullText(const Diagnostic &diagnostic)
|
||||
}
|
||||
|
||||
|
||||
DiagnosticItem::DiagnosticItem(const Diagnostic &diag) : m_diagnostic(diag)
|
||||
DiagnosticItem::DiagnosticItem(const Diagnostic &diag, const OnCheckedFixit &onCheckedFixit)
|
||||
: m_diagnostic(diag)
|
||||
, m_onCheckedFixit(onCheckedFixit)
|
||||
{
|
||||
// Don't show explaining steps if they add no information.
|
||||
if (diag.explainingSteps.count() == 1) {
|
||||
@@ -214,21 +220,15 @@ DiagnosticItem::DiagnosticItem(const Diagnostic &diag) : m_diagnostic(diag)
|
||||
|
||||
Qt::ItemFlags DiagnosticItem::flags(int column) const
|
||||
{
|
||||
if (column == DiagnosticView::FixItColumn && m_diagnostic.hasFixits)
|
||||
return TreeItem::flags(column) | Qt::ItemIsUserCheckable;
|
||||
return TreeItem::flags(column);
|
||||
}
|
||||
|
||||
static QVariant locationData(int role, const Debugger::DiagnosticLocation &location)
|
||||
{
|
||||
switch (role) {
|
||||
case Debugger::DetailedErrorView::LocationRole:
|
||||
return QVariant::fromValue(location);
|
||||
case Qt::ToolTipRole:
|
||||
return location.filePath.isEmpty() ? QVariant() : QVariant(location.filePath);
|
||||
default:
|
||||
return QVariant();
|
||||
const Qt::ItemFlags itemFlags = TreeItem::flags(column);
|
||||
if (column == DiagnosticView::FixItColumn) {
|
||||
if (m_diagnostic.hasFixits)
|
||||
return itemFlags | Qt::ItemIsUserCheckable;
|
||||
else
|
||||
return itemFlags & ~Qt::ItemIsEnabled;
|
||||
}
|
||||
|
||||
return itemFlags;
|
||||
}
|
||||
|
||||
static QVariant iconData(const QString &type)
|
||||
@@ -247,7 +247,7 @@ static QVariant iconData(const QString &type)
|
||||
QVariant DiagnosticItem::data(int column, int role) const
|
||||
{
|
||||
if (column == Debugger::DetailedErrorView::LocationColumn)
|
||||
return locationData(role, m_diagnostic.location);
|
||||
return Debugger::DetailedErrorView::locationData(role, m_diagnostic.location);
|
||||
|
||||
if (column == DiagnosticView::FixItColumn) {
|
||||
if (role == Qt::CheckStateRole)
|
||||
@@ -277,6 +277,8 @@ bool DiagnosticItem::setData(int column, const QVariant &data, int role)
|
||||
if (column == DiagnosticView::FixItColumn && role == Qt::CheckStateRole) {
|
||||
m_applyFixits = data.value<Qt::CheckState>() == Qt::Checked ? true : false;
|
||||
update();
|
||||
if (m_onCheckedFixit)
|
||||
m_onCheckedFixit(m_applyFixits);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -290,7 +292,7 @@ ExplainingStepItem::ExplainingStepItem(const ExplainingStep &step) : m_step(step
|
||||
QVariant ExplainingStepItem::data(int column, int role) const
|
||||
{
|
||||
if (column == Debugger::DetailedErrorView::LocationColumn)
|
||||
return locationData(role, m_step.location);
|
||||
return Debugger::DetailedErrorView::locationData(role, m_step.location);
|
||||
|
||||
if (column == DiagnosticView::FixItColumn)
|
||||
return QVariant();
|
||||
|
@@ -35,6 +35,8 @@
|
||||
#include <QPointer>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace ProjectExplorer { class Project; }
|
||||
|
||||
namespace ClangTools {
|
||||
@@ -43,7 +45,8 @@ namespace Internal {
|
||||
class DiagnosticItem : public Utils::TreeItem
|
||||
{
|
||||
public:
|
||||
DiagnosticItem(const Diagnostic &diag);
|
||||
using OnCheckedFixit = std::function<void(bool)>;
|
||||
DiagnosticItem(const Diagnostic &diag, const OnCheckedFixit &onCheckedFixit);
|
||||
|
||||
Diagnostic diagnostic() const { return m_diagnostic; }
|
||||
bool applyFixits() const { return m_applyFixits; }
|
||||
@@ -56,6 +59,7 @@ private:
|
||||
private:
|
||||
const Diagnostic m_diagnostic;
|
||||
bool m_applyFixits = false;
|
||||
OnCheckedFixit m_onCheckedFixit;
|
||||
};
|
||||
|
||||
class ClangToolsDiagnosticModel : public Utils::TreeModel<>
|
||||
@@ -71,6 +75,12 @@ public:
|
||||
enum ItemRole {
|
||||
DiagnosticRole = Debugger::DetailedErrorView::FullTextRole + 1
|
||||
};
|
||||
|
||||
signals:
|
||||
void fixItsToApplyCountChanged(int count);
|
||||
|
||||
private:
|
||||
int m_fixItsToApplyCount = 0;
|
||||
};
|
||||
|
||||
class DiagnosticFilterModel : public QSortFilterProxyModel
|
||||
|
@@ -196,6 +196,12 @@ void BuildDirManager::setParametersAndRequestParse(const BuildDirParameters &par
|
||||
int newReaderReparseOptions,
|
||||
int existingReaderReparseOptions)
|
||||
{
|
||||
if (!parameters.cmakeTool) {
|
||||
TaskHub::addTask(Task::Error,
|
||||
tr("The kit needs to define a CMake tool to parse this project."),
|
||||
ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
|
||||
return;
|
||||
}
|
||||
QTC_ASSERT(parameters.isValid(), return);
|
||||
|
||||
if (m_reader)
|
||||
|
@@ -279,8 +279,7 @@ static std::vector<std::unique_ptr<FileNode>> &&
|
||||
removeKnownNodes(const QSet<Utils::FileName> &knownFiles,
|
||||
std::vector<std::unique_ptr<FileNode>> &&files)
|
||||
{
|
||||
std::remove_if(std::begin(files), std::end(files),
|
||||
[&knownFiles](const std::unique_ptr<FileNode> &n) {
|
||||
Utils::erase(files, [&knownFiles](const std::unique_ptr<FileNode> &n) {
|
||||
return knownFiles.contains(n->filePath());
|
||||
});
|
||||
return std::move(files);
|
||||
|
@@ -19,6 +19,108 @@
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string notr="true">&Project Parts</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_12">
|
||||
<item>
|
||||
<widget class="QSplitter" name="projectPartsSplitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<widget class="QTabWidget" name="projectPartTab">
|
||||
<property name="currentIndex">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_17">
|
||||
<attribute name="title">
|
||||
<string notr="true">&General</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
<item>
|
||||
<widget class="QTreeView" name="partGeneralView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_13">
|
||||
<attribute name="title">
|
||||
<string notr="true">Project &Files</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_14">
|
||||
<item>
|
||||
<widget class="QTreeView" name="projectFilesView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_14">
|
||||
<attribute name="title">
|
||||
<string notr="true">&Defines</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_19">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string notr="true">Toolchain Defines</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_13">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="partToolchainDefinesEdit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string notr="true">Project Defines</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_15">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="partProjectDefinesEdit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_15">
|
||||
<attribute name="title">
|
||||
<string notr="true">&Header Paths</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_16">
|
||||
<item>
|
||||
<widget class="QTreeView" name="projectHeaderPathsView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_16">
|
||||
<attribute name="title">
|
||||
<string notr="true">Pre&compiled Headers</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_18">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="partPrecompiledHeadersEdit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string notr="true">&Snapshots and Documents</string>
|
||||
@@ -182,108 +284,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string notr="true">&Project Parts</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_12">
|
||||
<item>
|
||||
<widget class="QSplitter" name="projectPartsSplitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<widget class="QTabWidget" name="projectPartTab">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_17">
|
||||
<attribute name="title">
|
||||
<string notr="true">&General</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
<item>
|
||||
<widget class="QTreeView" name="partGeneralView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_13">
|
||||
<attribute name="title">
|
||||
<string notr="true">Project &Files</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_14">
|
||||
<item>
|
||||
<widget class="QTreeView" name="projectFilesView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_14">
|
||||
<attribute name="title">
|
||||
<string notr="true">&Defines</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_19">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string notr="true">Toolchain Defines</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_13">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="partToolchainDefinesEdit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string notr="true">Project Defines</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_15">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="partProjectDefinesEdit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_15">
|
||||
<attribute name="title">
|
||||
<string notr="true">&Header Paths</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_16">
|
||||
<item>
|
||||
<widget class="QTreeView" name="projectHeaderPathsView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_16">
|
||||
<attribute name="title">
|
||||
<string notr="true">Pre&compiled Headers</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_18">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="partPrecompiledHeadersEdit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_3">
|
||||
<attribute name="title">
|
||||
<string notr="true">&Working Copy</string>
|
||||
|
@@ -41,91 +41,14 @@
|
||||
#include <QHeaderView>
|
||||
#include <QMenu>
|
||||
#include <QPainter>
|
||||
#include <QSharedPointer>
|
||||
#include <QTextDocument>
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
class DetailedErrorDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DetailedErrorDelegate(QTreeView *parent) : QStyledItemDelegate(parent) { }
|
||||
|
||||
private:
|
||||
QString actualText(const QModelIndex &index) const
|
||||
{
|
||||
const auto location = index.model()->data(index, DetailedErrorView::LocationRole)
|
||||
.value<DiagnosticLocation>();
|
||||
return location.isValid()
|
||||
? QString::fromLatin1("<a href=\"file://%1\">%2:%3:%4")
|
||||
.arg(location.filePath, QFileInfo(location.filePath).fileName())
|
||||
.arg(location.line)
|
||||
.arg(location.column)
|
||||
: QString();
|
||||
}
|
||||
|
||||
using DocConstPtr = QSharedPointer<const QTextDocument>;
|
||||
DocConstPtr document(const QStyleOptionViewItem &option) const
|
||||
{
|
||||
const auto doc = QSharedPointer<QTextDocument>::create();
|
||||
doc->setHtml(option.text);
|
||||
doc->setTextWidth(option.rect.width());
|
||||
doc->setDocumentMargin(0);
|
||||
return doc;
|
||||
}
|
||||
|
||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
|
||||
{
|
||||
QStyleOptionViewItem opt = option;
|
||||
opt.text = actualText(index);
|
||||
initStyleOption(&opt, index);
|
||||
|
||||
const DocConstPtr doc = document(opt);
|
||||
return QSize(doc->idealWidth(), doc->size().height());
|
||||
}
|
||||
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override
|
||||
{
|
||||
QStyleOptionViewItem opt = option;
|
||||
initStyleOption(&opt, index);
|
||||
|
||||
QStyle *style = opt.widget? opt.widget->style() : QApplication::style();
|
||||
|
||||
// Painting item without text
|
||||
opt.text.clear();
|
||||
style->drawControl(QStyle::CE_ItemViewItem, &opt, painter);
|
||||
opt.text = actualText(index);
|
||||
|
||||
QAbstractTextDocumentLayout::PaintContext ctx;
|
||||
|
||||
// Highlighting text if item is selected
|
||||
if (opt.state & QStyle::State_Selected) {
|
||||
ctx.palette.setColor(QPalette::Text, opt.palette.color(QPalette::Active,
|
||||
QPalette::HighlightedText));
|
||||
}
|
||||
|
||||
QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &opt);
|
||||
painter->save();
|
||||
painter->translate(textRect.topLeft());
|
||||
painter->setClipRect(textRect.translated(-textRect.topLeft()));
|
||||
document(opt)->documentLayout()->draw(painter, ctx);
|
||||
painter->restore();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
|
||||
DetailedErrorView::DetailedErrorView(QWidget *parent) :
|
||||
QTreeView(parent),
|
||||
m_copyAction(new QAction(this))
|
||||
{
|
||||
header()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
setItemDelegateForColumn(LocationColumn, new Internal::DetailedErrorDelegate(this));
|
||||
|
||||
m_copyAction->setText(tr("Copy"));
|
||||
m_copyAction->setIcon(Utils::Icons::COPY.icon());
|
||||
@@ -187,6 +110,31 @@ void DetailedErrorView::goBack()
|
||||
setCurrentRow(prevRow >= 0 ? prevRow : rowCount() - 1);
|
||||
}
|
||||
|
||||
QVariant DetailedErrorView::locationData(int role, const DiagnosticLocation &location)
|
||||
{
|
||||
switch (role) {
|
||||
case Debugger::DetailedErrorView::LocationRole:
|
||||
return QVariant::fromValue(location);
|
||||
case Qt::DisplayRole:
|
||||
return location.isValid() ? QString::fromLatin1("%1:%2:%3")
|
||||
.arg(QFileInfo(location.filePath).fileName())
|
||||
.arg(location.line)
|
||||
.arg(location.column)
|
||||
: QString();
|
||||
case Qt::ToolTipRole:
|
||||
return location.filePath.isEmpty() ? QVariant() : QVariant(location.filePath);
|
||||
case Qt::FontRole: {
|
||||
QFont font = QApplication::font();
|
||||
font.setUnderline(true);
|
||||
return font;
|
||||
}
|
||||
case Qt::ForegroundRole:
|
||||
return QApplication::palette().link().color();
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
int DetailedErrorView::rowCount() const
|
||||
{
|
||||
return model() ? model()->rowCount() : 0;
|
||||
@@ -218,5 +166,3 @@ void DetailedErrorView::setCurrentRow(int row)
|
||||
}
|
||||
|
||||
} // namespace Debugger
|
||||
|
||||
#include "detailederrorview.moc"
|
||||
|
@@ -32,6 +32,8 @@
|
||||
|
||||
namespace Debugger {
|
||||
|
||||
class DiagnosticLocation;
|
||||
|
||||
class DEBUGGER_EXPORT DetailedErrorView : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -53,6 +55,8 @@ public:
|
||||
LocationColumn,
|
||||
};
|
||||
|
||||
static QVariant locationData(int role, const DiagnosticLocation &location);
|
||||
|
||||
private:
|
||||
void contextMenuEvent(QContextMenuEvent *e) override;
|
||||
void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) override;
|
||||
|
@@ -179,6 +179,7 @@ SideDiffEditorWidget::SideDiffEditorWidget(QWidget *parent)
|
||||
connect(documentLayout, &TextDocumentLayout::foldChanged,
|
||||
this, &SideDiffEditorWidget::foldChanged);
|
||||
setCodeFoldingSupported(true);
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
}
|
||||
|
||||
void SideDiffEditorWidget::saveState()
|
||||
@@ -714,6 +715,13 @@ SideBySideDiffEditorWidget::SideBySideDiffEditorWidget(QWidget *parent)
|
||||
connect(m_rightEditor, &SideDiffEditorWidget::foldChanged,
|
||||
m_leftEditor, &SideDiffEditorWidget::setFolded);
|
||||
|
||||
connect(m_leftEditor->horizontalScrollBar(), &QAbstractSlider::rangeChanged,
|
||||
this, &SideBySideDiffEditorWidget::syncHorizontalScrollBarPolicy);
|
||||
|
||||
connect(m_rightEditor->horizontalScrollBar(), &QAbstractSlider::rangeChanged,
|
||||
this, &SideBySideDiffEditorWidget::syncHorizontalScrollBarPolicy);
|
||||
|
||||
syncHorizontalScrollBarPolicy();
|
||||
|
||||
m_splitter = new MiniSplitter(this);
|
||||
m_splitter->addWidget(m_leftEditor);
|
||||
@@ -1133,6 +1141,18 @@ void SideBySideDiffEditorWidget::rightCursorPositionChanged()
|
||||
rightHSliderChanged();
|
||||
}
|
||||
|
||||
void SideBySideDiffEditorWidget::syncHorizontalScrollBarPolicy()
|
||||
{
|
||||
const bool alwaysOn = m_leftEditor->horizontalScrollBar()->maximum()
|
||||
|| m_rightEditor->horizontalScrollBar()->maximum();
|
||||
const Qt::ScrollBarPolicy newPolicy = alwaysOn
|
||||
? Qt::ScrollBarAlwaysOn : Qt::ScrollBarAsNeeded;
|
||||
if (m_leftEditor->horizontalScrollBarPolicy() != newPolicy)
|
||||
m_leftEditor->setHorizontalScrollBarPolicy(newPolicy);
|
||||
if (m_rightEditor->horizontalScrollBarPolicy() != newPolicy)
|
||||
m_rightEditor->setHorizontalScrollBarPolicy(newPolicy);
|
||||
}
|
||||
|
||||
void SideBySideDiffEditorWidget::handlePositionChange(SideDiffEditorWidget *source, SideDiffEditorWidget *dest)
|
||||
{
|
||||
if (m_controller.m_ignoreCurrentIndexChange)
|
||||
|
@@ -95,6 +95,7 @@ private:
|
||||
void rightHSliderChanged();
|
||||
void leftCursorPositionChanged();
|
||||
void rightCursorPositionChanged();
|
||||
void syncHorizontalScrollBarPolicy();
|
||||
void handlePositionChange(SideDiffEditorWidget *source, SideDiffEditorWidget *dest);
|
||||
void syncCursor(SideDiffEditorWidget *source, SideDiffEditorWidget *dest);
|
||||
|
||||
|
@@ -337,22 +337,4 @@ BuildStep *BuildStepFactory::restore(BuildStepList *parent, const QVariantMap &m
|
||||
return bs;
|
||||
}
|
||||
|
||||
BuildStep *BuildStepFactory::clone(BuildStepList *parent, BuildStep *product)
|
||||
{
|
||||
if ((m_info.flags & BuildStepInfo::Unclonable) != 0)
|
||||
return nullptr;
|
||||
if (m_info.id != product->id())
|
||||
return nullptr;
|
||||
BuildStep *bs = m_info.creator(parent);
|
||||
if (!bs)
|
||||
return nullptr;
|
||||
const QVariantMap map = product->toMap();
|
||||
if (!bs->fromMap(map)) {
|
||||
QTC_CHECK(false);
|
||||
delete bs;
|
||||
return nullptr;
|
||||
}
|
||||
return bs;
|
||||
}
|
||||
|
||||
} // ProjectExplorer
|
||||
|
@@ -132,7 +132,6 @@ public:
|
||||
Core::Id stepId() const;
|
||||
BuildStep *create(BuildStepList *parent, Core::Id id);
|
||||
BuildStep *restore(BuildStepList *parent, const QVariantMap &map);
|
||||
BuildStep *clone(BuildStepList *parent, BuildStep *product);
|
||||
|
||||
virtual bool canHandle(BuildStepList *bsl) const;
|
||||
|
||||
|
@@ -701,6 +701,11 @@ void Project::createTargetFromMap(const QVariantMap &map, int index)
|
||||
Target *t = restoreTarget(targetMap);
|
||||
if (!t)
|
||||
return;
|
||||
if (t->runConfigurations().isEmpty() && t->buildConfigurations().isEmpty()) {
|
||||
delete t;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
addTarget(t);
|
||||
}
|
||||
|
@@ -33,6 +33,7 @@
|
||||
|
||||
#include <coreplugin/messagebox.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QQmlContext>
|
||||
|
||||
@@ -135,15 +136,13 @@ QStringList PropertyEditorContextObject::autoComplete(const QString &text, int p
|
||||
|
||||
void PropertyEditorContextObject::toogleExportAlias()
|
||||
{
|
||||
if (!m_model || !m_model->rewriterView())
|
||||
return;
|
||||
QTC_ASSERT(m_model && m_model->rewriterView(), return);
|
||||
|
||||
/* Ideally we should not missuse the rewriterView
|
||||
* If we add more code here we have to forward the property editor view */
|
||||
RewriterView *rewriterView = m_model->rewriterView();
|
||||
|
||||
if (rewriterView->selectedModelNodes().isEmpty())
|
||||
return;
|
||||
QTC_ASSERT(!rewriterView->selectedModelNodes().isEmpty(), return);
|
||||
|
||||
const ModelNode selectedNode = rewriterView->selectedModelNodes().constFirst();
|
||||
|
||||
@@ -174,15 +173,13 @@ void PropertyEditorContextObject::toogleExportAlias()
|
||||
void PropertyEditorContextObject::changeTypeName(const QString &typeName)
|
||||
{
|
||||
|
||||
if (!m_model || !m_model->rewriterView())
|
||||
return;
|
||||
QTC_ASSERT(m_model && m_model->rewriterView(), return);
|
||||
|
||||
/* Ideally we should not missuse the rewriterView
|
||||
* If we add more code here we have to forward the property editor view */
|
||||
RewriterView *rewriterView = m_model->rewriterView();
|
||||
|
||||
if (rewriterView->selectedModelNodes().isEmpty())
|
||||
return;
|
||||
QTC_ASSERT(!rewriterView->selectedModelNodes().isEmpty(), return);
|
||||
|
||||
ModelNode selectedNode = rewriterView->selectedModelNodes().constFirst();
|
||||
|
||||
@@ -210,15 +207,13 @@ void PropertyEditorContextObject::changeTypeName(const QString &typeName)
|
||||
|
||||
void PropertyEditorContextObject::insertKeyframe(const QString &propertyName)
|
||||
{
|
||||
if (!m_model || !m_model->rewriterView())
|
||||
return;
|
||||
QTC_ASSERT(m_model && m_model->rewriterView(), return);
|
||||
|
||||
/* Ideally we should not missuse the rewriterView
|
||||
* If we add more code here we have to forward the property editor view */
|
||||
RewriterView *rewriterView = m_model->rewriterView();
|
||||
|
||||
if (rewriterView->selectedModelNodes().isEmpty())
|
||||
return;
|
||||
QTC_ASSERT(!rewriterView->selectedModelNodes().isEmpty(), return);
|
||||
|
||||
ModelNode selectedNode = rewriterView->selectedModelNodes().constFirst();
|
||||
|
||||
|
@@ -271,6 +271,8 @@ void PropertyEditorQmlBackend::setup(const QmlObjectNode &qmlObjectNode, const Q
|
||||
|
||||
if (qmlObjectNode.isValid()) {
|
||||
|
||||
m_contextObject->setModel(propertyEditor->model());
|
||||
|
||||
qCInfo(propertyEditorBenchmark) << Q_FUNC_INFO;
|
||||
|
||||
QTime time;
|
||||
|
@@ -90,8 +90,8 @@ void QmlJSTextMark::init(bool warning, const QString message)
|
||||
{
|
||||
setIcon(warning ? Utils::Icons::CODEMODEL_WARNING.icon()
|
||||
: Utils::Icons::CODEMODEL_ERROR.icon());
|
||||
setColor(warning ? Utils::Theme::ClangCodeModel_Warning_TextMarkColor
|
||||
: Utils::Theme::ClangCodeModel_Error_TextMarkColor);
|
||||
setColor(warning ? Utils::Theme::CodeModel_Warning_TextMarkColor
|
||||
: Utils::Theme::CodeModel_Error_TextMarkColor);
|
||||
setDefaultToolTip(warning ? QApplication::translate("QmlJS Code Model Marks", "Code Model Warning")
|
||||
: QApplication::translate("QmlJS Code Model Marks", "Code Model Error"));
|
||||
setToolTip(message);
|
||||
|
@@ -5363,7 +5363,6 @@ void TextEditorWidgetPrivate::updateCurrentLineInScrollbar()
|
||||
{
|
||||
if (m_highlightCurrentLine && m_highlightScrollBarController) {
|
||||
m_highlightScrollBarController->removeHighlights(Constants::SCROLL_BAR_CURRENT_LINE);
|
||||
if (m_highlightScrollBarController->scrollBar()->maximum() > 0) {
|
||||
const QTextCursor &tc = q->textCursor();
|
||||
if (QTextLayout *layout = tc.block().layout()) {
|
||||
const int pos = q->textCursor().block().firstLineNumber() +
|
||||
@@ -5373,7 +5372,6 @@ void TextEditorWidgetPrivate::updateCurrentLineInScrollbar()
|
||||
Highlight::HighestPriority});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextEditorWidgetPrivate::slotUpdateBlockNotify(const QTextBlock &block)
|
||||
|
@@ -173,24 +173,16 @@ ErrorItem::ErrorItem(const ErrorListModel *model, const Error &error)
|
||||
}
|
||||
}
|
||||
|
||||
static QVariant location(const Frame &frame, int role)
|
||||
static QVariant locationData(int role, const Frame &frame)
|
||||
{
|
||||
switch (role) {
|
||||
case Debugger::DetailedErrorView::LocationRole:
|
||||
return QVariant::fromValue(Debugger::DiagnosticLocation(frame.filePath(), frame.line(), 0));
|
||||
case Qt::ToolTipRole:
|
||||
return frame.filePath().isEmpty() ? QVariant() : QVariant(frame.filePath());
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
const Debugger::DiagnosticLocation location(frame.filePath(), frame.line(), 0);
|
||||
return Debugger::DetailedErrorView::locationData(role, location);
|
||||
}
|
||||
|
||||
QVariant ErrorItem::data(int column, int role) const
|
||||
{
|
||||
if (column == Debugger::DetailedErrorView::LocationColumn) {
|
||||
const Frame frame = m_model->findRelevantFrame(m_error);
|
||||
return location(frame, role);
|
||||
}
|
||||
if (column == Debugger::DetailedErrorView::LocationColumn)
|
||||
return locationData(role, m_model->findRelevantFrame(m_error));
|
||||
|
||||
// DiagnosticColumn
|
||||
switch (role) {
|
||||
@@ -243,7 +235,7 @@ QVariant StackItem::data(int column, int role) const
|
||||
{
|
||||
const ErrorItem * const errorItem = getErrorItem();
|
||||
if (column == Debugger::DetailedErrorView::LocationColumn)
|
||||
return location(errorItem->modelPrivate()->findRelevantFrame(errorItem->error()), role);
|
||||
return locationData(role, errorItem->modelPrivate()->findRelevantFrame(errorItem->error()));
|
||||
|
||||
// DiagnosticColumn
|
||||
switch (role) {
|
||||
@@ -271,7 +263,7 @@ FrameItem::FrameItem(const Frame &frame) : m_frame(frame)
|
||||
QVariant FrameItem::data(int column, int role) const
|
||||
{
|
||||
if (column == Debugger::DetailedErrorView::LocationColumn)
|
||||
return location(m_frame, role);
|
||||
return locationData(role, m_frame);
|
||||
|
||||
// DiagnosticColumn
|
||||
switch (role) {
|
||||
|
@@ -101,10 +101,10 @@ isEmpty(LLVM_VERSION) {
|
||||
$$llvmWarningOrError(\
|
||||
"Cannot determine clang version. Set LLVM_INSTALL_DIR to build the Clang Code Model",\
|
||||
"LLVM_INSTALL_DIR does not contain a valid llvm-config, candidate: $$llvm_config")
|
||||
} else:!versionIsAtLeast($$LLVM_VERSION, 5, 0, 0): {
|
||||
} else:!versionIsAtLeast($$LLVM_VERSION, 6, 0, 0): {
|
||||
# CLANG-UPGRADE-CHECK: Adapt minimum version numbers.
|
||||
$$llvmWarningOrError(\
|
||||
"LLVM/Clang version >= 5.0.0 required, version provided: $$LLVM_VERSION")
|
||||
"LLVM/Clang version >= 6.0.0 required, version provided: $$LLVM_VERSION")
|
||||
LLVM_VERSION =
|
||||
} else {
|
||||
LLVM_LIBDIR = $$quote($$system($$llvm_config --libdir, lines))
|
||||
@@ -141,11 +141,11 @@ isEmpty(LLVM_VERSION) {
|
||||
QTC_NO_CLANG_LIBTOOLING=$$(QTC_NO_CLANG_LIBTOOLING)
|
||||
isEmpty(QTC_NO_CLANG_LIBTOOLING) {
|
||||
QTC_FORCE_CLANG_LIBTOOLING = $$(QTC_FORCE_CLANG_LIBTOOLING)
|
||||
versionIsEqual($$LLVM_VERSION, 5, 0)|!isEmpty(QTC_FORCE_CLANG_LIBTOOLING) {
|
||||
versionIsEqual($$LLVM_VERSION, 6, 0)|!isEmpty(QTC_FORCE_CLANG_LIBTOOLING) {
|
||||
!contains(QMAKE_DEFAULT_LIBDIRS, $$LLVM_LIBDIR): LIBTOOLING_LIBS = -L$${LLVM_LIBDIR}
|
||||
LIBTOOLING_LIBS += $$CLANGTOOLING_LIBS $$LLVM_STATIC_LIBS
|
||||
} else {
|
||||
warning("Clang LibTooling is disabled because only version 5.0 is supported.")
|
||||
warning("Clang LibTooling is disabled because only version 6.0 is supported.")
|
||||
}
|
||||
} else {
|
||||
warning("Clang LibTooling is disabled.")
|
||||
|
@@ -163,8 +163,7 @@ static const char *builtinTypeToText(CXTypeKind kind)
|
||||
|
||||
// https://gcc.gnu.org/onlinedocs/gcc/Floating-Types.html
|
||||
case CXType_Float128: return "__float128";
|
||||
// CLANG-UPGRADE-CHECK: CXType_Float16 available with >= clang-6.0:
|
||||
// case CXType_Float16: return "_Float16";
|
||||
case CXType_Float16: return "_Float16";
|
||||
|
||||
// https://www.khronos.org/registry/OpenCL/sdk/2.1/docs/man/xhtml/scalarDataTypes.html
|
||||
case CXType_Half:
|
||||
|
@@ -93,8 +93,6 @@ SourceLocation::SourceLocation(CXTranslationUnit cxTranslationUnit,
|
||||
return;
|
||||
|
||||
filePath_ = ClangString(clang_getFileName(cxFile));
|
||||
// CLANG-UPGRADE-CHECK: Remove HAS_GETFILECONTENTS_BACKPORTED check once we require clang >= 7.0
|
||||
#if defined(CINDEX_VERSION_HAS_GETFILECONTENTS_BACKPORTED) || CINDEX_VERSION_MINOR >= 47
|
||||
if (column_ > 1) {
|
||||
const uint lineStart = offset_ + 1 - column_;
|
||||
const char *contents = clang_getFileContents(cxTranslationUnit, cxFile, nullptr);
|
||||
@@ -106,7 +104,6 @@ SourceLocation::SourceLocation(CXTranslationUnit cxTranslationUnit,
|
||||
column_ = static_cast<uint>(QString::fromUtf8(&contents[lineStart],
|
||||
static_cast<int>(column_)).size());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SourceLocation::SourceLocation(CXTranslationUnit cxTranslationUnit,
|
||||
|
@@ -19,7 +19,7 @@ include($$PWD/../../../src/shared/clang/clang_defines.pri)
|
||||
include($$PWD/../../../src/tools/clangbackend/source/clangbackendclangipc-source.pri)
|
||||
include($$PWD/../../../src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri)
|
||||
} else {
|
||||
DEFINES += CLANG_VERSION=\\\"5.0.0\\\"
|
||||
DEFINES += CLANG_VERSION=\\\"6.0.0\\\"
|
||||
DEFINES += "\"CLANG_RESOURCE_DIR=\\\"/usr/include\\\"\""
|
||||
}
|
||||
|
||||
|
@@ -148,7 +148,7 @@ TEST_F(SkippedSourceRanges, DISABLED_ON_WINDOWS(RangeOne))
|
||||
{
|
||||
auto ranges = skippedSourceRanges.sourceRanges();
|
||||
|
||||
ASSERT_THAT(ranges[0].start(), IsSourceLocation(filePath, 1, 2, 1));
|
||||
ASSERT_THAT(ranges[0].start(), IsSourceLocation(filePath, 1, 1, 0));
|
||||
ASSERT_THAT(ranges[0].end(), IsSourceLocation(filePath, 5, 1, 18));
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ TEST_F(SkippedSourceRanges, DISABLED_ON_WINDOWS(RangeTwo))
|
||||
{
|
||||
auto ranges = skippedSourceRanges.sourceRanges();
|
||||
|
||||
ASSERT_THAT(ranges[1].start(), IsSourceLocation(filePath, 7, 2, 27));
|
||||
ASSERT_THAT(ranges[1].start(), IsSourceLocation(filePath, 7, 1, 26));
|
||||
ASSERT_THAT(ranges[1].end(), IsSourceLocation(filePath, 12, 1, 57));
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user