forked from OSchip/llvm-project
[flang] Added -fget-definitions and -fget-all-symbols.
- -fget-definitions finds the definition of the symbol under specified source position. - -fget-all-symbols finds definition locations of all symbols in a document. For symbols found in other modules, shows which module the symbol came from. - Tests. - New structure SourcePosition with file, line, column information. Original-commit: flang-compiler/f18@e0099b0900 Reviewed-on: https://github.com/flang-compiler/f18/pull/698 Tree-same-pre-rewrite: false
This commit is contained in:
parent
99fb2cfc2f
commit
2f205a5f52
|
@ -111,6 +111,17 @@ ProvenanceRange OffsetToProvenanceMappings::Map(std::size_t at) const {
|
|||
return provenanceMap_[low].range.Suffix(offset);
|
||||
}
|
||||
|
||||
std::optional<std::size_t> OffsetToProvenanceMappings::ReverseMap(
|
||||
Provenance at) const {
|
||||
for (const auto &[start, range] : provenanceMap_) {
|
||||
if (range.Contains(at)) {
|
||||
std::size_t offset{at.offset() - range.start().offset()};
|
||||
return start + offset;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void OffsetToProvenanceMappings::RemoveLastBytes(std::size_t bytes) {
|
||||
for (; bytes > 0; provenanceMap_.pop_back()) {
|
||||
CHECK(!provenanceMap_.empty());
|
||||
|
@ -306,6 +317,26 @@ const SourceFile *AllSources::GetSourceFile(
|
|||
origin.u);
|
||||
}
|
||||
|
||||
std::optional<SourcePosition> AllSources::GetSourcePosition(
|
||||
Provenance prov) const {
|
||||
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};
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<ProvenanceRange> AllSources::GetFirstFileProvenance() const {
|
||||
for (const auto &origin : origin_) {
|
||||
if (std::holds_alternative<Inclusion>(origin.u)) {
|
||||
return origin.covers;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::string AllSources::GetPath(Provenance at) const {
|
||||
const SourceFile *source{GetSourceFile(at)};
|
||||
return source ? source->path() : ""s;
|
||||
|
@ -412,6 +443,42 @@ std::optional<CharBlock> CookedSource::GetCharBlock(
|
|||
}
|
||||
}
|
||||
|
||||
std::optional<CharBlock> CookedSource::GetCharBlockFromLineAndColumns(
|
||||
int line, int startColumn, int endColumn) const {
|
||||
// 2nd column is exclusive, meaning it is target column + 1.
|
||||
CHECK(line > 0 && startColumn > 0 && endColumn > 0);
|
||||
auto provenanceStart{allSources_.GetFirstFileProvenance().value().start()};
|
||||
if (auto sourceFile{allSources_.GetSourceFile(provenanceStart)}) {
|
||||
CHECK(line <= static_cast<int>(sourceFile->lines()));
|
||||
if (auto firstOffset{
|
||||
provenanceMap_.ReverseMap(sourceFile->GetLineStartOffset(line) +
|
||||
provenanceStart.offset() + startColumn - 1)}) {
|
||||
if (auto secondOffset{
|
||||
provenanceMap_.ReverseMap(sourceFile->GetLineStartOffset(line) +
|
||||
provenanceStart.offset() + endColumn - 2)}) {
|
||||
if (*secondOffset >= *firstOffset) {
|
||||
// Returned 2nd column is also exclusive.
|
||||
return CharBlock(
|
||||
&data_[*firstOffset], *secondOffset - *firstOffset + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::pair<SourcePosition, SourcePosition>>
|
||||
CookedSource::GetSourcePositionRange(CharBlock cookedRange) const {
|
||||
if (auto range{GetProvenanceRange(cookedRange)}) {
|
||||
if (auto firstOffset{allSources_.GetSourcePosition(range->start())}) {
|
||||
if (auto secondOffset{
|
||||
allSources_.GetSourcePosition(range->start() + range->size())}) {
|
||||
return std::pair{*firstOffset, *secondOffset};
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void CookedSource::Marshal() {
|
||||
CHECK(provenanceMap_.SizeInBytes() == buffer_.bytes());
|
||||
provenanceMap_.Put(allSources_.AddCompilerInsertion("(after end of source)"));
|
||||
|
|
|
@ -52,8 +52,6 @@ namespace Fortran::parser {
|
|||
// by the upper bits of an offset, but that does not appear to be
|
||||
// necessary.)
|
||||
|
||||
class AllSources;
|
||||
|
||||
class Provenance {
|
||||
public:
|
||||
Provenance() {}
|
||||
|
@ -124,6 +122,7 @@ public:
|
|||
void Put(ProvenanceRange);
|
||||
void Put(const OffsetToProvenanceMappings &);
|
||||
ProvenanceRange Map(std::size_t at) const;
|
||||
std::optional<std::size_t> ReverseMap(Provenance) const;
|
||||
void RemoveLastBytes(std::size_t);
|
||||
ProvenanceRangeToOffsetMappings Invert(const AllSources &) const;
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
@ -139,6 +138,17 @@ 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 {
|
||||
|
@ -173,6 +183,8 @@ public:
|
|||
const std::string &message, bool echoSourceLine = false) const;
|
||||
const SourceFile *GetSourceFile(
|
||||
Provenance, std::size_t *offset = nullptr) const;
|
||||
std::optional<SourcePosition> GetSourcePosition(Provenance) const;
|
||||
std::optional<ProvenanceRange> GetFirstFileProvenance();
|
||||
std::string GetPath(Provenance) const; // __FILE__
|
||||
int GetLineNumber(Provenance) const; // __LINE__
|
||||
Provenance CompilerInsertionProvenance(char ch);
|
||||
|
@ -237,6 +249,10 @@ public:
|
|||
|
||||
std::optional<ProvenanceRange> GetProvenanceRange(CharBlock) const;
|
||||
std::optional<CharBlock> GetCharBlock(ProvenanceRange) const;
|
||||
std::optional<CharBlock> GetCharBlockFromLineAndColumns(
|
||||
int line, int startColumn, int endColumn) const;
|
||||
std::optional<std::pair<SourcePosition, SourcePosition>>
|
||||
GetSourcePositionRange(CharBlock) const;
|
||||
|
||||
// The result of a Put() is the offset that the new data
|
||||
// will have in the eventually marshaled contiguous buffer.
|
||||
|
|
|
@ -40,7 +40,9 @@
|
|||
|
||||
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);
|
||||
|
||||
// A parse tree visitor that calls Enter/Leave functions from each checker
|
||||
|
@ -268,6 +270,36 @@ 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 << " ";
|
||||
|
|
|
@ -181,6 +181,7 @@ public:
|
|||
bool AnyFatalError() const { return context_.AnyFatalError(); }
|
||||
void EmitMessages(std::ostream &) const;
|
||||
void DumpSymbols(std::ostream &);
|
||||
void DumpSymbolsSources(std::ostream &) const;
|
||||
|
||||
private:
|
||||
SemanticsContext &context_;
|
||||
|
|
|
@ -244,6 +244,18 @@ set(FORALL_TESTS
|
|||
forall*.[Ff]90
|
||||
)
|
||||
|
||||
set(GETSYMBOLS_TESTS
|
||||
getsymbols01.f90
|
||||
getsymbols02-*.f90
|
||||
getsymbols03-a.f90
|
||||
)
|
||||
|
||||
set(GETDEFINITION_TESTS
|
||||
getdefinition01.f90
|
||||
getdefinition02.f
|
||||
getdefinition03-a.f90
|
||||
)
|
||||
|
||||
set(F18 $<TARGET_FILE:f18>)
|
||||
|
||||
foreach(test ${ERROR_TESTS})
|
||||
|
@ -261,7 +273,8 @@ foreach(test ${MODFILE_TESTS})
|
|||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test_modfile.sh ${test} ${F18})
|
||||
endforeach()
|
||||
|
||||
foreach(test ${LABEL_TESTS} ${CANONDO_TESTS} ${DOCONCURRENT_TESTS} ${FORALL_TESTS})
|
||||
foreach(test ${LABEL_TESTS} ${CANONDO_TESTS} ${DOCONCURRENT_TESTS}
|
||||
${FORALL_TESTS} ${GETSYMBOLS_TESTS} ${GETDEFINITION_TESTS})
|
||||
add_test(NAME ${test}
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test_any.sh ${test} ${F18})
|
||||
endforeach()
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
! 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 returning source position of symbol definition.
|
||||
|
||||
!DEF: /m Module
|
||||
module m
|
||||
!DEF: /m/f PRIVATE, PURE, RECURSIVE Subprogram REAL(4)
|
||||
private :: f
|
||||
contains
|
||||
!DEF: /m/s BIND(C), PUBLIC, PURE Subprogram
|
||||
!DEF: /m/s/x INTENT(IN) (implicit) ObjectEntity REAL(4)
|
||||
!DEF: /m/s/y INTENT(INOUT) (implicit) ObjectEntity REAL(4)
|
||||
pure subroutine s (x, yyy) bind(c)
|
||||
!REF: /m/s/x
|
||||
intent(in) :: x
|
||||
!REF: /m/s/y
|
||||
intent(inout) :: yyy
|
||||
contains
|
||||
!DEF: /m/s/ss PURE Subprogram
|
||||
pure subroutine ss
|
||||
end subroutine
|
||||
end subroutine
|
||||
!REF: /m/f
|
||||
!DEF: /m/f/x ALLOCATABLE ObjectEntity REAL(4)
|
||||
recursive pure function f() result(x)
|
||||
!REF: /m/f/x
|
||||
real, allocatable :: x
|
||||
!REF: /m/f/x
|
||||
x = 1.0
|
||||
end function
|
||||
end module
|
||||
|
||||
! RUN: echo %t 1>&2;
|
||||
! RUN: ${F18} -fget-definition 27 17 18 -fparse-only -fdebug-semantics %s > %t;
|
||||
! RUN: ${F18} -fget-definition 29 20 23 -fparse-only -fdebug-semantics %s >> %t;
|
||||
! RUN: ${F18} -fget-definition 41 3 4 -fparse-only -fdebug-semantics %s >> %t;
|
||||
! RUN: ${F18} -fget-definition -fparse-only -fdebug-semantics %s >> %t 2>&1;
|
||||
! RUN: cat %t | ${FileCheck} %s
|
||||
! CHECK:x:.*getdefinition01.f90, 25, 21-22
|
||||
! CHECK:yyy:.*getdefinition01.f90, 25, 24-27
|
||||
! CHECK:x:.*getdefinition01.f90, 39, 24-25
|
||||
! CHECK:Invalid argument to -fget-definitions
|
|
@ -0,0 +1,52 @@
|
|||
! 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 fixed form.
|
||||
|
||||
!DEF: /m Module
|
||||
module m
|
||||
!DEF: /m/f PRIVATE, PURE, RECURSIVE Subprogram REAL(4)
|
||||
private :: f
|
||||
contains
|
||||
!DEF: /m/s BIND(C), PUBLIC, PURE Subprogram
|
||||
!DEF: /m/s/x INTENT(IN) (implicit) ObjectEntity REAL(4)
|
||||
!DEF: /m/s/y INTENT(INOUT) (implicit) ObjectEntity REAL(4)
|
||||
pure subroutine s (x, yyy) bind(c)
|
||||
!REF: /m/s/x
|
||||
intent(in) ::
|
||||
* x
|
||||
!REF: /m/s/y
|
||||
intent(inout) :: yyy
|
||||
contains
|
||||
!DEF: /m/s/ss PURE Subprogram
|
||||
pure subroutine ss
|
||||
end subroutine
|
||||
end subroutine
|
||||
!REF: /m/f
|
||||
!DEF: /m/f/x ALLOCATABLE ObjectEntity REAL(4)
|
||||
recursive pure function f() result(x)
|
||||
!REF: /m/f/x
|
||||
real, allocatable :: x
|
||||
!REF: /m/f/x
|
||||
x = 1.0
|
||||
end function
|
||||
end module
|
||||
|
||||
! RUN: ${F18} -fget-definition 28 9 10 -fparse-only -fdebug-semantics %s > %t;
|
||||
! RUN: ${F18} -fget-definition 30 26 29 -fparse-only -fdebug-semantics %s >> %t;
|
||||
! RUN: ${F18} -fget-definition 42 9 10 -fparse-only -fdebug-semantics %s >> %t;
|
||||
! RUN: cat %t | ${FileCheck} %s
|
||||
! CHECK:x:.*getdefinition02.f, 25, 27-28
|
||||
! CHECK:yyy:.*getdefinition02.f, 25, 30-33
|
||||
! CHECK:x:.*getdefinition02.f, 40, 30-31
|
|
@ -0,0 +1,29 @@
|
|||
! 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 INCLUDE
|
||||
|
||||
INCLUDE "getdefinition03-b.f90"
|
||||
|
||||
program main
|
||||
use m
|
||||
integer :: x
|
||||
x = f
|
||||
end program
|
||||
|
||||
! RUN: ${F18} -fget-definition 22 6 7 -fparse-only -fdebug-semantics %s > %t;
|
||||
! RUN: ${F18} -fget-definition 22 2 3 -fparse-only -fdebug-semantics %s >> %t;
|
||||
! RUN: cat %t | ${FileCheck} %s;
|
||||
! CHECK:f:.*getdefinition03-b.f90, 16, 12-13
|
||||
! CHECK:x:.*getdefinition03-a.f90, 21, 13-14
|
|
@ -0,0 +1,17 @@
|
|||
! 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.
|
||||
|
||||
module m
|
||||
public :: f
|
||||
end module
|
|
@ -0,0 +1,52 @@
|
|||
! 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 finding all symbols in file.
|
||||
|
||||
!DEF: /m Module
|
||||
module m
|
||||
!DEF: /m/f PRIVATE, PURE, RECURSIVE Subprogram REAL(4)
|
||||
private :: f
|
||||
contains
|
||||
!DEF: /m/s BIND(C), PUBLIC, PURE Subprogram
|
||||
!DEF: /m/s/x INTENT(IN) (implicit) ObjectEntity REAL(4)
|
||||
!DEF: /m/s/y INTENT(INOUT) (implicit) ObjectEntity REAL(4)
|
||||
pure subroutine s (x, y) bind(c)
|
||||
!REF: /m/s/x
|
||||
intent(in) :: x
|
||||
!REF: /m/s/y
|
||||
intent(inout) :: y
|
||||
contains
|
||||
!DEF: /m/s/ss PURE Subprogram
|
||||
pure subroutine ss
|
||||
end subroutine
|
||||
end subroutine
|
||||
!REF: /m/f
|
||||
!DEF: /m/f/x ALLOCATABLE ObjectEntity REAL(4)
|
||||
recursive pure function f() result(x)
|
||||
!REF: /m/f/x
|
||||
real, allocatable :: x
|
||||
!REF: /m/f/x
|
||||
x = 1.0
|
||||
end function
|
||||
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
|
|
@ -0,0 +1,26 @@
|
|||
! 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.
|
||||
|
||||
! RUN: ${F18} -fparse-only -fdebug-semantics %s
|
||||
|
||||
module m2
|
||||
implicit none
|
||||
private
|
||||
public :: get5
|
||||
contains
|
||||
function get5() result(ret)
|
||||
integer :: ret
|
||||
ret = 5
|
||||
end function get5
|
||||
end module m2
|
|
@ -0,0 +1,28 @@
|
|||
! 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.
|
||||
|
||||
! RUN: ${F18} -fparse-only -fdebug-semantics %s
|
||||
|
||||
module m1
|
||||
use m2
|
||||
implicit none
|
||||
private
|
||||
public :: callget5
|
||||
contains
|
||||
function callget5() result(ret)
|
||||
implicit none
|
||||
INTEGER :: ret
|
||||
ret = get5()
|
||||
end function callget5
|
||||
end module m1
|
|
@ -0,0 +1,26 @@
|
|||
! 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 modules.
|
||||
|
||||
PROGRAM helloworld
|
||||
use m1
|
||||
implicit none
|
||||
integer::i
|
||||
i = callget5()
|
||||
ENDPROGRAM
|
||||
|
||||
! RUN: ${F18} -fget-symbols-sources -fparse-only -fdebug-semantics %s 2>&1 | ${FileCheck} %s
|
||||
! CHECK:callget5: m1
|
||||
! CHECK:get5: m2
|
|
@ -0,0 +1,29 @@
|
|||
! 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 with INCLUDE
|
||||
|
||||
INCLUDE "getsymbols03-b.f90"
|
||||
|
||||
program main
|
||||
use m
|
||||
integer :: x
|
||||
x = f
|
||||
end program
|
||||
|
||||
! RUN: ${F18} -fget-symbols-sources -fparse-only -fdebug-semantics %s 2>&1 | ${FileCheck} %s
|
||||
! CHECK:m:.*getsymbols03-b.f90, 15, 8-9
|
||||
! CHECK:f:.*getsymbols03-b.f90, 16, 12-13
|
||||
! CHECK:main:.*getsymbols03-a.f90, 19, 9-13
|
||||
! CHECK:x:.*getsymbols03-a.f90, 21, 13-14
|
|
@ -0,0 +1,17 @@
|
|||
! 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.
|
||||
|
||||
module m
|
||||
public :: f
|
||||
end module
|
|
@ -53,6 +53,10 @@ gr=0
|
|||
for input in ${srcdir}/$*; do
|
||||
CMD=$(cat ${input} | egrep '^[[:space:]]*![[:space:]]*RUN:[[:space:]]*' | sed -e 's/^[[:space:]]*![[:space:]]*RUN:[[:space:]]*//')
|
||||
CMD=$(echo ${CMD} | sed -e "s:%s:${input}:g")
|
||||
if egrep -q -e '%t' <<< ${CMD} ; then
|
||||
temp=`mktemp`
|
||||
CMD=$(echo ${CMD} | sed -e "s:%t:${temp}:g")
|
||||
fi
|
||||
if $(eval $CMD); then
|
||||
echo "PASS ${input}"
|
||||
else
|
||||
|
|
|
@ -101,6 +101,9 @@ struct DriverOptions {
|
|||
bool unparseTypedExprsToPGF90{false};
|
||||
std::vector<std::string> pgf90Args;
|
||||
const char *prefix{nullptr};
|
||||
bool getDefinition{false};
|
||||
int getDefinitionArgs[3]; // line, startColumn, endColumn.
|
||||
bool getSymbolsSources{false};
|
||||
};
|
||||
|
||||
bool ParentProcess() {
|
||||
|
@ -226,7 +229,8 @@ std::string CompileFortran(std::string path, Fortran::parser::Options options,
|
|||
}
|
||||
// TODO: Change this predicate to just "if (!driver.debugNoSemantics)"
|
||||
if (driver.debugSemantics || driver.debugResolveNames || driver.dumpSymbols ||
|
||||
driver.dumpUnparseWithSymbols) {
|
||||
driver.dumpUnparseWithSymbols || driver.getDefinition ||
|
||||
driver.getSymbolsSources) {
|
||||
Fortran::semantics::Semantics semantics{
|
||||
semanticsContext, parseTree, parsing.cooked()};
|
||||
semantics.Perform();
|
||||
|
@ -247,6 +251,45 @@ std::string CompileFortran(std::string path, Fortran::parser::Options options,
|
|||
std::cout, parseTree, driver.encoding);
|
||||
return {};
|
||||
}
|
||||
if (driver.getSymbolsSources) {
|
||||
semantics.DumpSymbolsSources(std::cout);
|
||||
return {};
|
||||
}
|
||||
if (driver.getDefinition) {
|
||||
std::string notFoundText{"Symbol not found.\n"};
|
||||
auto cb{parsing.cooked().GetCharBlockFromLineAndColumns(
|
||||
driver.getDefinitionArgs[0], driver.getDefinitionArgs[1],
|
||||
driver.getDefinitionArgs[2])};
|
||||
if (!cb) {
|
||||
std::cerr << notFoundText;
|
||||
exitStatus = EXIT_FAILURE;
|
||||
return {};
|
||||
}
|
||||
std::cerr << "String range: >" << std::string(cb->begin(), cb->size())
|
||||
<< "<\n";
|
||||
auto &scope{semanticsContext.FindScope(*cb)};
|
||||
auto symbol{scope.FindSymbol(*cb)};
|
||||
if (!symbol) {
|
||||
std::cerr << notFoundText;
|
||||
exitStatus = EXIT_FAILURE;
|
||||
return {};
|
||||
}
|
||||
std::cerr << "Found symbol name: "
|
||||
<< std::string(symbol->name().begin(), symbol->name().size())
|
||||
<< "\n";
|
||||
auto sourceInfo{parsing.cooked().GetSourcePositionRange(symbol->name())};
|
||||
if (!sourceInfo) {
|
||||
std::cerr << notFoundText;
|
||||
exitStatus = EXIT_FAILURE;
|
||||
return {};
|
||||
}
|
||||
std::cout << symbol->name().ToString() << ": "
|
||||
<< sourceInfo->first.file.path() << ", "
|
||||
<< sourceInfo->first.line << ", " << sourceInfo->first.column
|
||||
<< "-" << sourceInfo->second.column << "\n";
|
||||
exitStatus = EXIT_SUCCESS;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
if (driver.dumpParseTree) {
|
||||
Fortran::parser::DumpTree(std::cout, parseTree);
|
||||
|
@ -479,6 +522,26 @@ int main(int argc, char *const argv[]) {
|
|||
driver.encoding = Fortran::parser::Encoding::UTF_8;
|
||||
} else if (arg == "-flatin") {
|
||||
driver.encoding = Fortran::parser::Encoding::LATIN_1;
|
||||
} else if (arg == "-fget-definition") {
|
||||
// Receives 3 arguments: line, startColumn, endColumn.
|
||||
driver.getDefinition = true;
|
||||
char *endptr;
|
||||
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);
|
||||
if (*endptr != '\0') {
|
||||
std::cerr << "Invalid argument to -fget-definitions: " << args.front()
|
||||
<< '\n';
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
args.pop_front();
|
||||
}
|
||||
} else if (arg == "-fget-symbols-sources") {
|
||||
driver.getSymbolsSources = true;
|
||||
} else if (arg == "-help" || arg == "--help" || arg == "-?") {
|
||||
std::cerr
|
||||
<< "f18 options:\n"
|
||||
|
@ -506,6 +569,8 @@ int main(int argc, char *const argv[]) {
|
|||
<< " -fdebug-resolve-names\n"
|
||||
<< " -fdebug-instrumented-parse\n"
|
||||
<< " -fdebug-semantics perform semantic checks\n"
|
||||
<< " -fget-definition\n"
|
||||
<< " -fget-symbols-sources\n"
|
||||
<< " -v -c -o -I -D -U have their usual meanings\n"
|
||||
<< " -help print this again\n"
|
||||
<< "Other options are passed through to the compiler.\n";
|
||||
|
|
Loading…
Reference in New Issue