forked from OSchip/llvm-project
[flang] FindOffsetLineAndColumn also uses SourcePosition.
New tests for COMMON and BLOCK. Added CHECK-ONCE to test_any.sh. Make sure pattern only occurs once. Original-commit: flang-compiler/f18@ad82dafcf9 Reviewed-on: https://github.com/flang-compiler/f18/pull/698 Tree-same-pre-rewrite: false
This commit is contained in:
parent
2f205a5f52
commit
69fd49a002
|
@ -239,18 +239,18 @@ void AllSources::EmitMessage(std::ostream &o,
|
|||
[&](const Inclusion &inc) {
|
||||
o << inc.source.path();
|
||||
std::size_t offset{origin.covers.MemberOffset(range->start())};
|
||||
std::pair<int, int> pos{inc.source.FindOffsetLineAndColumn(offset)};
|
||||
o << ':' << pos.first << ':' << pos.second;
|
||||
SourcePosition pos{inc.source.FindOffsetLineAndColumn(offset)};
|
||||
o << ':' << pos.line << ':' << pos.column;
|
||||
o << ": " << message << '\n';
|
||||
if (echoSourceLine) {
|
||||
const char *text{inc.source.content() +
|
||||
inc.source.GetLineStartOffset(pos.first)};
|
||||
inc.source.GetLineStartOffset(pos.line)};
|
||||
o << " ";
|
||||
for (const char *p{text}; *p != '\n'; ++p) {
|
||||
o << *p;
|
||||
}
|
||||
o << "\n ";
|
||||
for (int j{1}; j < pos.second; ++j) {
|
||||
for (int j{1}; j < pos.column; ++j) {
|
||||
char ch{text[j - 1]};
|
||||
o << (ch == '\t' ? '\t' : ' ');
|
||||
}
|
||||
|
@ -260,8 +260,8 @@ void AllSources::EmitMessage(std::ostream &o,
|
|||
if (&MapToOrigin(last) == &origin) {
|
||||
auto endOffset{origin.covers.MemberOffset(last)};
|
||||
auto endPos{inc.source.FindOffsetLineAndColumn(endOffset)};
|
||||
if (pos.first == endPos.first) {
|
||||
for (int j{pos.second}; j < endPos.second; ++j) {
|
||||
if (pos.line == endPos.line) {
|
||||
for (int j{pos.column}; j < endPos.column; ++j) {
|
||||
o << '^';
|
||||
}
|
||||
}
|
||||
|
@ -322,7 +322,7 @@ std::optional<SourcePosition> AllSources::GetSourcePosition(
|
|||
const Origin &origin{MapToOrigin(prov)};
|
||||
if (const auto *inc{std::get_if<Inclusion>(&origin.u)}) {
|
||||
std::size_t offset{origin.covers.MemberOffset(prov)};
|
||||
return SourcePosition{inc->source, offset};
|
||||
return inc->source.FindOffsetLineAndColumn(offset);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
@ -345,7 +345,7 @@ std::string AllSources::GetPath(Provenance at) const {
|
|||
int AllSources::GetLineNumber(Provenance at) const {
|
||||
std::size_t offset{0};
|
||||
const SourceFile *source{GetSourceFile(at, &offset)};
|
||||
return source ? source->FindOffsetLineAndColumn(offset).first : 0;
|
||||
return source ? source->FindOffsetLineAndColumn(offset).line : 0;
|
||||
}
|
||||
|
||||
Provenance AllSources::CompilerInsertionProvenance(char ch) {
|
||||
|
|
|
@ -138,17 +138,6 @@ private:
|
|||
std::vector<ContiguousProvenanceMapping> provenanceMap_;
|
||||
};
|
||||
|
||||
struct SourcePosition {
|
||||
SourcePosition(const SourceFile &file, int line, int column)
|
||||
: file{file}, line{line}, column{column} {}
|
||||
SourcePosition(const SourceFile &file, std::pair<int, int> pos)
|
||||
: file{file}, line{pos.first}, column{pos.second} {}
|
||||
SourcePosition(const SourceFile &, std::size_t);
|
||||
|
||||
const SourceFile &file;
|
||||
int line, column;
|
||||
};
|
||||
|
||||
// A singleton AllSources instance for the whole compilation
|
||||
// is shared by reference.
|
||||
class AllSources {
|
||||
|
|
|
@ -256,10 +256,10 @@ void SourceFile::Close() {
|
|||
path_.clear();
|
||||
}
|
||||
|
||||
std::pair<int, int> SourceFile::FindOffsetLineAndColumn(std::size_t at) const {
|
||||
SourcePosition SourceFile::FindOffsetLineAndColumn(std::size_t at) const {
|
||||
CHECK(at < bytes_);
|
||||
if (lineStart_.empty()) {
|
||||
return {1, static_cast<int>(at + 1)};
|
||||
return {*this, 1, static_cast<int>(at + 1)};
|
||||
}
|
||||
std::size_t low{0}, count{lineStart_.size()};
|
||||
while (count > 1) {
|
||||
|
@ -271,7 +271,7 @@ std::pair<int, int> SourceFile::FindOffsetLineAndColumn(std::size_t at) const {
|
|||
low = mid;
|
||||
}
|
||||
}
|
||||
return {
|
||||
static_cast<int>(low + 1), static_cast<int>(at - lineStart_[low] + 1)};
|
||||
return {*this, static_cast<int>(low + 1),
|
||||
static_cast<int>(at - lineStart_[low] + 1)};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,18 @@ std::string DirectoryName(std::string path);
|
|||
std::string LocateSourceFile(
|
||||
std::string name, const std::vector<std::string> &searchPath);
|
||||
|
||||
class SourceFile;
|
||||
|
||||
struct SourcePosition {
|
||||
SourcePosition(const SourceFile &file, int line, int column)
|
||||
: file{file}, line{line}, column{column} {}
|
||||
SourcePosition(const SourceFile &file, std::pair<int, int> pos)
|
||||
: file{file}, line{pos.first}, column{pos.second} {}
|
||||
|
||||
const SourceFile &file;
|
||||
int line, column;
|
||||
};
|
||||
|
||||
class SourceFile {
|
||||
public:
|
||||
explicit SourceFile(Encoding e) : encoding_{e} {}
|
||||
|
@ -46,7 +58,7 @@ public:
|
|||
bool Open(std::string path, std::stringstream *error);
|
||||
bool ReadStandardInput(std::stringstream *error);
|
||||
void Close();
|
||||
std::pair<int, int> FindOffsetLineAndColumn(std::size_t) const;
|
||||
SourcePosition FindOffsetLineAndColumn(std::size_t) const;
|
||||
std::size_t GetLineStartOffset(int lineNumber) const {
|
||||
return lineStart_.at(lineNumber - 1);
|
||||
}
|
||||
|
|
|
@ -42,9 +42,21 @@ namespace Fortran::semantics {
|
|||
|
||||
using NameToSymbolMap = std::map<const char *, const Symbol *>;
|
||||
static void DoDumpSymbols(std::ostream &, const Scope &, int indent = 0);
|
||||
static void GetSymbolNames(const Scope &, NameToSymbolMap &);
|
||||
static void PutIndent(std::ostream &, int indent);
|
||||
|
||||
static void GetSymbolNames(const Scope &scope, NameToSymbolMap &symbols) {
|
||||
// Finds all symbol names in the scope without collecting duplicates.
|
||||
for (const auto &pair : scope) {
|
||||
symbols.emplace(pair.second->name().begin(), pair.second);
|
||||
}
|
||||
for (const auto &pair : scope.commonBlocks()) {
|
||||
symbols.emplace(pair.second->name().begin(), pair.second);
|
||||
}
|
||||
for (const auto &child : scope.children()) {
|
||||
GetSymbolNames(child, symbols);
|
||||
}
|
||||
}
|
||||
|
||||
// A parse tree visitor that calls Enter/Leave functions from each checker
|
||||
// class C supplied as template parameters. Enter is called before the node's
|
||||
// children are visited, Leave is called after. No two checkers may have the
|
||||
|
@ -219,6 +231,23 @@ void Semantics::DumpSymbols(std::ostream &os) {
|
|||
DoDumpSymbols(os, context_.globalScope());
|
||||
}
|
||||
|
||||
void Semantics::DumpSymbolsSources(std::ostream &os) const {
|
||||
NameToSymbolMap symbols;
|
||||
GetSymbolNames(context_.globalScope(), symbols);
|
||||
for (const auto pair : symbols) {
|
||||
const Symbol &symbol{*pair.second};
|
||||
auto sourceInfo{cooked_.GetSourcePositionRange(symbol.name())};
|
||||
if (sourceInfo) {
|
||||
os << symbol.name().ToString() << ": " << sourceInfo->first.file.path()
|
||||
<< ", " << sourceInfo->first.line << ", " << sourceInfo->first.column
|
||||
<< "-" << sourceInfo->second.column << "\n";
|
||||
} else if (symbol.has<semantics::UseDetails>()) {
|
||||
os << symbol.name().ToString() << ": "
|
||||
<< symbol.GetUltimate().owner().symbol()->name().ToString() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoDumpSymbols(std::ostream &os, const Scope &scope, int indent) {
|
||||
PutIndent(os, indent);
|
||||
os << Scope::EnumToString(scope.kind()) << " scope:";
|
||||
|
@ -270,36 +299,6 @@ void DoDumpSymbols(std::ostream &os, const Scope &scope, int indent) {
|
|||
--indent;
|
||||
}
|
||||
|
||||
void Semantics::DumpSymbolsSources(std::ostream &os) const {
|
||||
NameToSymbolMap symbols;
|
||||
GetSymbolNames(context_.globalScope(), symbols);
|
||||
for (const auto pair : symbols) {
|
||||
const Symbol &symbol{*pair.second};
|
||||
auto sourceInfo{cooked_.GetSourcePositionRange(symbol.name())};
|
||||
if (sourceInfo) {
|
||||
os << symbol.name().ToString() << ": " << sourceInfo->first.file.path()
|
||||
<< ", " << sourceInfo->first.line << ", " << sourceInfo->first.column
|
||||
<< "-" << sourceInfo->second.column << "\n";
|
||||
} else if (symbol.has<semantics::UseDetails>()) {
|
||||
os << symbol.name().ToString() << ": "
|
||||
<< symbol.GetUltimate().owner().symbol()->name().ToString() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GetSymbolNames(const Scope &scope, NameToSymbolMap &symbols) {
|
||||
// Finds all symbol names in the scope without collecting duplicates.
|
||||
for (const auto &pair : scope) {
|
||||
symbols.emplace(pair.second->name().begin(), pair.second);
|
||||
}
|
||||
for (const auto &pair : scope.commonBlocks()) {
|
||||
symbols.emplace(pair.second->name().begin(), pair.second);
|
||||
}
|
||||
for (const auto &child : scope.children()) {
|
||||
GetSymbolNames(child, symbols);
|
||||
}
|
||||
}
|
||||
|
||||
static void PutIndent(std::ostream &os, int indent) {
|
||||
for (int i = 0; i < indent; ++i) {
|
||||
os << " ";
|
||||
|
|
|
@ -248,12 +248,16 @@ set(GETSYMBOLS_TESTS
|
|||
getsymbols01.f90
|
||||
getsymbols02-*.f90
|
||||
getsymbols03-a.f90
|
||||
getsymbols04.f90
|
||||
getsymbols05.f90
|
||||
)
|
||||
|
||||
set(GETDEFINITION_TESTS
|
||||
getdefinition01.f90
|
||||
getdefinition02.f
|
||||
getdefinition03-a.f90
|
||||
getdefinition04.f90
|
||||
getdefinition05.f90
|
||||
)
|
||||
|
||||
set(F18 $<TARGET_FILE:f18>)
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
! Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
!
|
||||
! Licensed under the Apache License, Version 2.0 (the "License");
|
||||
! you may not use this file except in compliance with the License.
|
||||
! You may obtain a copy of the License at
|
||||
!
|
||||
! http://www.apache.org/licenses/LICENSE-2.0
|
||||
!
|
||||
! Unless required by applicable law or agreed to in writing, software
|
||||
! distributed under the License is distributed on an "AS IS" BASIS,
|
||||
! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
! See the License for the specific language governing permissions and
|
||||
! limitations under the License.
|
||||
|
||||
! Tests -fget-definition with COMMON block with same name as variable.
|
||||
|
||||
program main
|
||||
integer :: x
|
||||
integer :: y
|
||||
common /x/ y
|
||||
x = y
|
||||
end program
|
||||
|
||||
! RUN: ${F18} -fget-definition 21 3 4 -fparse-only -fdebug-semantics %s | ${FileCheck} %s
|
||||
! CHECK:x:.*getdefinition04.f90, 18, 14-15
|
|
@ -0,0 +1,35 @@
|
|||
! Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
!
|
||||
! Licensed under the Apache License, Version 2.0 (the "License");
|
||||
! you may not use this file except in compliance with the License.
|
||||
! You may obtain a copy of the License at
|
||||
!
|
||||
! http://www.apache.org/licenses/LICENSE-2.0
|
||||
!
|
||||
! Unless required by applicable law or agreed to in writing, software
|
||||
! distributed under the License is distributed on an "AS IS" BASIS,
|
||||
! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
! See the License for the specific language governing permissions and
|
||||
! limitations under the License.
|
||||
|
||||
! Tests -fget-symbols-sources with BLOCK that contains same variable name as
|
||||
! another in an outer scope.
|
||||
|
||||
program main
|
||||
integer :: x
|
||||
integer :: y
|
||||
block
|
||||
integer :: x
|
||||
integer :: y
|
||||
x = y
|
||||
end block
|
||||
x = y
|
||||
end program
|
||||
|
||||
!! Inner x
|
||||
! RUN: ${F18} -fget-definition 24 5 6 -fparse-only -fdebug-semantics %s > %t;
|
||||
! CHECK:x:.*getdefinition05.f90, 22, 16-17
|
||||
!! Outer y
|
||||
! RUN: ${F18} -fget-definition 26 7 8 -fparse-only -fdebug-semantics %s >> %t;
|
||||
! CHECK:y:.*getdefinition05.f90, 20, 14-15
|
||||
! RUN: cat %t | ${FileCheck} %s;
|
|
@ -43,10 +43,10 @@ contains
|
|||
end module
|
||||
|
||||
! RUN: ${F18} -fget-symbols-sources -fparse-only -fdebug-semantics %s 2>&1 | ${FileCheck} %s
|
||||
! CHECK:m:.*getsymbols01.f90, 18, 8-9
|
||||
! CHECK:f:.*getsymbols01.f90, 37, 26-27
|
||||
! CHECK:s:.*getsymbols01.f90, 25, 18-19
|
||||
! CHECK:ss:.*getsymbols01.f90, 32, 19-21
|
||||
! CHECK:x:.*getsymbols01.f90, 25, 21-22
|
||||
! CHECK:y:.*getsymbols01.f90, 25, 24-25
|
||||
! CHECK:x:.*getsymbols01.f90, 39, 24-25
|
||||
! CHECK-ONCE:m:.*getsymbols01.f90, 18, 8-9
|
||||
! CHECK-ONCE:f:.*getsymbols01.f90, 37, 26-27
|
||||
! CHECK-ONCE:s:.*getsymbols01.f90, 25, 18-19
|
||||
! CHECK-ONCE:ss:.*getsymbols01.f90, 32, 19-21
|
||||
! CHECK-ONCE:x:.*getsymbols01.f90, 25, 21-22
|
||||
! CHECK-ONCE:y:.*getsymbols01.f90, 25, 24-25
|
||||
! CHECK-ONCE:x:.*getsymbols01.f90, 39, 24-25
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
! Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
!
|
||||
! Licensed under the Apache License, Version 2.0 (the "License");
|
||||
! you may not use this file except in compliance with the License.
|
||||
! You may obtain a copy of the License at
|
||||
!
|
||||
! http://www.apache.org/licenses/LICENSE-2.0
|
||||
!
|
||||
! Unless required by applicable law or agreed to in writing, software
|
||||
! distributed under the License is distributed on an "AS IS" BASIS,
|
||||
! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
! See the License for the specific language governing permissions and
|
||||
! limitations under the License.
|
||||
|
||||
! Tests -fget-symbols-sources with COMMON.
|
||||
|
||||
program main
|
||||
integer :: x
|
||||
integer :: y
|
||||
common /x/ y
|
||||
x = y
|
||||
end program
|
||||
|
||||
! RUN: ${F18} -fget-symbols-sources -fparse-only -fdebug-semantics %s 2>&1 | ${FileCheck} %s
|
||||
! CHECK:x:.*getsymbols04.f90, 18, 14-15
|
||||
! CHECK:y:.*getsymbols04.f90, 19, 14-15
|
||||
! CHECK:x:.*getsymbols04.f90, 20, 11-12
|
|
@ -0,0 +1,30 @@
|
|||
! Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
!
|
||||
! Licensed under the Apache License, Version 2.0 (the "License");
|
||||
! you may not use this file except in compliance with the License.
|
||||
! You may obtain a copy of the License at
|
||||
!
|
||||
! http://www.apache.org/licenses/LICENSE-2.0
|
||||
!
|
||||
! Unless required by applicable law or agreed to in writing, software
|
||||
! distributed under the License is distributed on an "AS IS" BASIS,
|
||||
! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
! See the License for the specific language governing permissions and
|
||||
! limitations under the License.
|
||||
|
||||
! Tests -fget-symbols-sources with COMMON.
|
||||
|
||||
program main
|
||||
integer :: x
|
||||
integer :: y
|
||||
block
|
||||
integer :: x
|
||||
x = y
|
||||
end block
|
||||
x = y
|
||||
end program
|
||||
|
||||
! RUN: ${F18} -fget-symbols-sources -fparse-only -fdebug-semantics %s 2>&1 | ${FileCheck} %s
|
||||
! CHECK:x:.*getsymbols05.f90, 18, 14-15
|
||||
! CHECK:y:.*getsymbols05.f90, 19, 14-15
|
||||
! CHECK:x:.*getsymbols05.f90, 21, 16-17
|
|
@ -45,6 +45,18 @@ function internal_check() {
|
|||
r=false
|
||||
fi
|
||||
done < ${lcheck}
|
||||
egrep '^[[:space:]]*![[:space:]]*CHECK-ONCE:[[:space:]]*' ${linput} | sed -e 's/^[[:space:]]*![[:space:]]*CHECK-ONCE:[[:space:]]*//' > ${lcheck} 2>/dev/null
|
||||
while read p; do
|
||||
count=$(egrep -o -e "${p}" ${lstdin} | wc -l)
|
||||
if [ ${count} -eq 0 ]; then
|
||||
echo "Not found: ${p}" >&2
|
||||
r=false
|
||||
fi
|
||||
if [ ${count} -gt 1 ]; then
|
||||
echo "Found duplicates: ${p}" >&2
|
||||
r=false
|
||||
fi
|
||||
done < ${lcheck}
|
||||
rm -f ${lstdin} ${lcheck}
|
||||
${r}
|
||||
}
|
||||
|
@ -55,6 +67,7 @@ for input in ${srcdir}/$*; do
|
|||
CMD=$(echo ${CMD} | sed -e "s:%s:${input}:g")
|
||||
if egrep -q -e '%t' <<< ${CMD} ; then
|
||||
temp=`mktemp`
|
||||
trap "rm -f ${temp}" EXIT
|
||||
CMD=$(echo ${CMD} | sed -e "s:%t:${temp}:g")
|
||||
fi
|
||||
if $(eval $CMD); then
|
||||
|
|
|
@ -76,6 +76,12 @@ void CleanUpAtExit() {
|
|||
}
|
||||
}
|
||||
|
||||
struct GetDefinitionArgs {
|
||||
GetDefinitionArgs(int line, int startColumn, int endColumn)
|
||||
: line{line}, startColumn{startColumn}, endColumn{endColumn} {}
|
||||
int line, startColumn, endColumn;
|
||||
};
|
||||
|
||||
struct DriverOptions {
|
||||
DriverOptions() {}
|
||||
bool verbose{false}; // -v
|
||||
|
@ -102,7 +108,7 @@ struct DriverOptions {
|
|||
std::vector<std::string> pgf90Args;
|
||||
const char *prefix{nullptr};
|
||||
bool getDefinition{false};
|
||||
int getDefinitionArgs[3]; // line, startColumn, endColumn.
|
||||
GetDefinitionArgs getDefinitionArgs{0, 0, 0};
|
||||
bool getSymbolsSources{false};
|
||||
};
|
||||
|
||||
|
@ -258,8 +264,8 @@ std::string CompileFortran(std::string path, Fortran::parser::Options options,
|
|||
if (driver.getDefinition) {
|
||||
std::string notFoundText{"Symbol not found.\n"};
|
||||
auto cb{parsing.cooked().GetCharBlockFromLineAndColumns(
|
||||
driver.getDefinitionArgs[0], driver.getDefinitionArgs[1],
|
||||
driver.getDefinitionArgs[2])};
|
||||
driver.getDefinitionArgs.line, driver.getDefinitionArgs.startColumn,
|
||||
driver.getDefinitionArgs.endColumn)};
|
||||
if (!cb) {
|
||||
std::cerr << notFoundText;
|
||||
exitStatus = EXIT_FAILURE;
|
||||
|
@ -526,13 +532,13 @@ int main(int argc, char *const argv[]) {
|
|||
// Receives 3 arguments: line, startColumn, endColumn.
|
||||
driver.getDefinition = true;
|
||||
char *endptr;
|
||||
int arguments[3];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (args.empty()) {
|
||||
std::cerr << "Must provide 3 arguments for -fget-definitions.\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
driver.getDefinitionArgs[i] =
|
||||
std::strtol(args.front().c_str(), &endptr, 10);
|
||||
arguments[i] = std::strtol(args.front().c_str(), &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
std::cerr << "Invalid argument to -fget-definitions: " << args.front()
|
||||
<< '\n';
|
||||
|
@ -540,6 +546,7 @@ int main(int argc, char *const argv[]) {
|
|||
}
|
||||
args.pop_front();
|
||||
}
|
||||
driver.getDefinitionArgs = {arguments[0], arguments[1], arguments[2]};
|
||||
} else if (arg == "-fget-symbols-sources") {
|
||||
driver.getSymbolsSources = true;
|
||||
} else if (arg == "-help" || arg == "--help" || arg == "-?") {
|
||||
|
|
Loading…
Reference in New Issue