[clang] a21a462 - Make the diagnostic-missing-prototypes put the suggested `static` in front of `const` if exists.
Vy Nguyen via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 9 16:35:21 PDT 2020
Author: Vy Nguyen
Date: 2020-06-09T19:34:57-04:00
New Revision: a21a462051659d8e1281af7d11738b8abc0557dc
URL: https://github.com/llvm/llvm-project/commit/a21a462051659d8e1281af7d11738b8abc0557dc
DIFF: https://github.com/llvm/llvm-project/commit/a21a462051659d8e1281af7d11738b8abc0557dc.diff
LOG: Make the diagnostic-missing-prototypes put the suggested `static` in front of `const` if exists.
Summary:
Consider: `const int* get_foo() {return nullptr;}`
The suggested fix should be `static const int* get_foo(){}`
and not `const static int* get_foo(){}`
Reviewers: gribozavr2
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D81444
Added:
Modified:
clang/lib/Sema/SemaDecl.cpp
clang/test/Sema/warn-missing-prototypes.c
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 401aea355c41..e6d4222d4b17 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14243,11 +14243,48 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
: FixItHint{});
}
} else {
+ // Returns true if the token beginning at this Loc is `const`.
+ auto isLocAtConst = [&](SourceLocation Loc, const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ if (LocInfo.first.isInvalid())
+ return false;
+
+ bool Invalid = false;
+ StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
+ if (Invalid)
+ return false;
+
+ if (LocInfo.second > Buffer.size())
+ return false;
+
+ const char *LexStart = Buffer.data() + LocInfo.second;
+ StringRef StartTok(LexStart, Buffer.size() - LocInfo.second);
+
+ return StartTok.consume_front("const") &&
+ (StartTok.empty() || isWhitespace(StartTok[0]) ||
+ StartTok.startswith("/*") || StartTok.startswith("//"));
+ };
+
+ auto findBeginLoc = [&]() {
+ // If the return type has `const` qualifier, we want to insert
+ // `static` before `const` (and not before the typename).
+ if ((FD->getReturnType()->isAnyPointerType() &&
+ FD->getReturnType()->getPointeeType().isConstQualified()) ||
+ FD->getReturnType().isConstQualified()) {
+ // But only do this if we can determine where the `const` is.
+
+ if (isLocAtConst(FD->getBeginLoc(), getSourceManager(),
+ getLangOpts()))
+
+ return FD->getBeginLoc();
+ }
+ return FD->getTypeSpecStartLoc();
+ };
Diag(FD->getTypeSpecStartLoc(), diag::note_static_for_internal_linkage)
<< /* function */ 1
<< (FD->getStorageClass() == SC_None
- ? FixItHint::CreateInsertion(FD->getTypeSpecStartLoc(),
- "static ")
+ ? FixItHint::CreateInsertion(findBeginLoc(), "static ")
: FixItHint{});
}
diff --git a/clang/test/Sema/warn-missing-prototypes.c b/clang/test/Sema/warn-missing-prototypes.c
index 5940a49572ba..1830b3ff9e73 100644
--- a/clang/test/Sema/warn-missing-prototypes.c
+++ b/clang/test/Sema/warn-missing-prototypes.c
@@ -49,3 +49,60 @@ int main(void) { return 0; }
void not_a_prototype_test(); // expected-note{{this declaration is not a prototype; add 'void' to make it a prototype for a zero-parameter function}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:27-[[@LINE-1]]:27}:"void"
void not_a_prototype_test() { } // expected-warning{{no previous prototype for function 'not_a_prototype_test'}}
+
+const int *get_const() { // expected-warning{{no previous prototype for function 'get_const'}}
+ // expected-note at -1{{declare 'static' if the function is not intended to be used outside of this translation unit}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:1-[[@LINE-2]]:1}:"static "
+ return (void *)0;
+}
+
+struct MyStruct {};
+
+const struct MyStruct get_struct() { // expected-warning{{no previous prototype for function 'get_struct'}}
+ // expected-note at -1{{declare 'static' if the function is not intended to be used outside of this translation unit}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:1-[[@LINE-2]]:1}:"static "
+ struct MyStruct ret;
+ return ret;
+}
+
+// Turn off clang-format for white-space dependent testing.
+// clang-format off
+// Two spaces between cost and struct
+const struct MyStruct get_struct_2() { // expected-warning{{no previous prototype for function 'get_struct_2'}}
+ // expected-note at -1{{declare 'static' if the function is not intended to be used outside of this translation unit}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:1-[[@LINE-2]]:1}:"static "
+ struct MyStruct ret;
+ return ret;
+}
+
+// Two spaces bewteen const and struct
+const struct MyStruct* get_struct_ptr() { // expected-warning{{no previous prototype for function 'get_struct_ptr'}}
+ // expected-note at -1{{declare 'static' if the function is not intended to be used outside of this translation unit}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:1-[[@LINE-2]]:1}:"static "
+ return (void*)0;
+}
+
+// Random comment before const.
+/*some randome comment*/const struct MyStruct* get_struct_3() { // expected-warning{{no previous prototype for function 'get_struct_3'}}
+ // expected-note at -1{{declare 'static' if the function is not intended to be used outside of this translation unit}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:25-[[@LINE-2]]:25}:"static "
+ return (void*)0;
+}
+
+// Random comment after const.
+const/*some randome comment*/ struct MyStruct* get_struct_4() { // expected-warning{{no previous prototype for function 'get_struct_4'}}
+ // expected-note at -1{{declare 'static' if the function is not intended to be used outside of this translation unit}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:1-[[@LINE-2]]:1}:"static "
+ return (void*)0;
+}
+// clang-format on
+
+#define MY_CONST const
+
+// Since we can't easily understand what MY_CONST means while preparing the
+// diagnostic, the fix-it suggests to add 'static' in a non-idiomatic place.
+MY_CONST struct MyStruct *get_struct_nyi() { // expected-warning{{no previous prototype for function 'get_struct_nyi'}}
+ // expected-note at -1{{declare 'static' if the function is not intended to be used outside of this translation unit}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static "
+ return (void *)0;
+}
More information about the cfe-commits
mailing list