Index: clang/include/clang/Basic/SourceManager.h =================================================================== --- clang/include/clang/Basic/SourceManager.h +++ clang/include/clang/Basic/SourceManager.h @@ -1390,10 +1390,14 @@ /// returns zero if the column number isn't known. This may only be called /// on a file sloc, so you must choose a spelling or expansion location /// before calling this method. + /// /param UseTabsStopOption when true tabs will count for TabsStop + /// (-ftabstop=x). otherwise tabs are counted as 1. unsigned getColumnNumber(FileID FID, unsigned FilePos, - bool *Invalid = nullptr) const; + bool *Invalid = nullptr, + bool UseTabsStopOption = false) const; unsigned getSpellingColumnNumber(SourceLocation Loc, - bool *Invalid = nullptr) const; + bool *Invalid = nullptr, + bool UseTabsStopOption = false) const; unsigned getExpansionColumnNumber(SourceLocation Loc, bool *Invalid = nullptr) const; unsigned getPresumedColumnNumber(SourceLocation Loc, Index: clang/lib/Basic/SourceManager.cpp =================================================================== --- clang/lib/Basic/SourceManager.cpp +++ clang/lib/Basic/SourceManager.cpp @@ -1149,7 +1149,8 @@ /// getColumnNumber - Return the column # for the specified file position. /// this is significantly cheaper to compute than the line number. unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos, - bool *Invalid) const { + bool *Invalid, + bool UseTabsStopOption) const { bool MyInvalid = false; const llvm::MemoryBuffer *MemBuf = getBuffer(FID, &MyInvalid); if (Invalid) @@ -1170,7 +1171,8 @@ // that to lookup the start of the line instead of searching for it. if (LastLineNoFileIDQuery == FID && LastLineNoContentCache->SourceLineCache != nullptr && - LastLineNoResult < LastLineNoContentCache->NumLines) { + LastLineNoResult < LastLineNoContentCache->NumLines && + !UseTabsStopOption) { unsigned *SourceLineCache = LastLineNoContentCache->SourceLineCache; unsigned LineStart = SourceLineCache[LastLineNoResult - 1]; unsigned LineEnd = SourceLineCache[LastLineNoResult]; @@ -1187,10 +1189,22 @@ } } + unsigned TabStop = + UseTabsStopOption ? getDiagnostics().getDiagnosticOptions().TabStop : 1; + unsigned LineStart = FilePos; - while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r') + while (LineStart && Buf[LineStart - 1] != '\n' && Buf[LineStart - 1] != '\r') --LineStart; - return FilePos-LineStart+1; + if (TabStop == 1) + return FilePos - LineStart + 1; + unsigned VirtualCharCount = 0; + while (LineStart <= FilePos) { + LineStart++; + VirtualCharCount = Buf[LineStart - 1] == '\t' + ? llvm::alignTo(VirtualCharCount + 1, TabStop) + : VirtualCharCount + 1; + } + return VirtualCharCount; } // isInvalid - Return the result of calling loc.isInvalid(), and @@ -1204,10 +1218,13 @@ } unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc, - bool *Invalid) const { - if (isInvalid(Loc, Invalid)) return 0; + bool *Invalid, + bool UseTabsStopOption) const { + if (isInvalid(Loc, Invalid)) + return 0; std::pair LocInfo = getDecomposedSpellingLoc(Loc); - return getColumnNumber(LocInfo.first, LocInfo.second, Invalid); + return getColumnNumber(LocInfo.first, LocInfo.second, Invalid, + UseTabsStopOption); } unsigned SourceManager::getExpansionColumnNumber(SourceLocation Loc, Index: clang/lib/Parse/ParseStmt.cpp =================================================================== --- clang/lib/Parse/ParseStmt.cpp +++ clang/lib/Parse/ParseStmt.cpp @@ -1226,11 +1226,16 @@ P.MisleadingIndentationElseLoc = SourceLocation(); return; } + if (Kind == MSK_else) + P.MisleadingIndentationElseLoc = SourceLocation(); SourceManager &SM = P.getPreprocessor().getSourceManager(); - unsigned PrevColNum = SM.getSpellingColumnNumber(PrevLoc); - unsigned CurColNum = SM.getSpellingColumnNumber(Tok.getLocation()); - unsigned StmtColNum = SM.getSpellingColumnNumber(StmtLoc); + unsigned PrevColNum = + SM.getSpellingColumnNumber(PrevLoc, nullptr, /*UseTabStop*/ true); + unsigned CurColNum = SM.getSpellingColumnNumber(Tok.getLocation(), nullptr, + /*UseTabStop*/ true); + unsigned StmtColNum = + SM.getSpellingColumnNumber(StmtLoc, nullptr, /*UseTabStop*/ true); if (PrevColNum != 0 && CurColNum != 0 && StmtColNum != 0 && ((PrevColNum > StmtColNum && PrevColNum == CurColNum) || Index: clang/test/Parser/warn-misleading-indentation.cpp =================================================================== --- clang/test/Parser/warn-misleading-indentation.cpp +++ clang/test/Parser/warn-misleading-indentation.cpp @@ -1,7 +1,9 @@ -// RUN: %clang_cc1 -x c -fsyntax-only -verify %s -// RUN: %clang_cc1 -x c -fsyntax-only -verify -Wmisleading-indentation -DWITH_WARN %s -// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify -Wall -Wno-unused -DWITH_WARN -DCXX17 %s -// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify -Wall -Wno-unused -Wno-misleading-indentation -DCXX17 %s +// RUNA: %clang_cc1 -x c -fsyntax-only -verify %s +// RUNA: %clang_cc1 -x c -fsyntax-only -verify -Wmisleading-indentation -DWITH_WARN -ftabstop 8 -DTAB_SIZE=8 %s +// RUNA: %clang_cc1 -std=c++17 -fsyntax-only -verify -Wall -Wno-unused -DWITH_WARN -DCXX17 %s +// RUNA: %clang_cc1 -std=c++17 -fsyntax-only -verify -Wall -Wno-unused -Wno-misleading-indentation -DCXX17 -ftabstop 4 -DTAB_SIZE=4 %s +// RUNA: %clang_cc1 -x c -fsyntax-only -verify -Wall -Wno-unused -DWITH_WARN -ftabstop 1 -DTAB_SIZE=1 %s +// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify -Wall -Wno-unused -Wmisleading-indentation -DCXX17 -DWITH_WARN -ftabstop 2 -DTAB_SIZE=2 %s #ifndef WITH_WARN // expected-no-diagnostics @@ -205,4 +207,37 @@ i = 4; } return; -} \ No newline at end of file +} + +int a4() +{ + if (0) + return 1; + return 0; +#if (TAB_SIZE == 1) +// expected-warning@-2 {{misleading indentation; statement is not part of the previous 'if'}} +// expected-note@-5 {{here}} +#endif +} + +int a5() +{ + if (0) + return 1; + return 0; +#if WITH_WARN +// expected-warning@-2 {{misleading indentation; statement is not part of the previous 'if'}} +// expected-note@-5 {{here}} +#endif +} + +int a6() +{ + if (0) + return 1; + return 0; +#if (TAB_SIZE == 4) +// expected-warning@-2 {{misleading indentation; statement is not part of the previous 'if'}} +// expected-note@-5 {{here}} +#endif +}