github.com/googleapis/api-linter@v1.65.2/locations/locations.go (about)

     1  // Copyright 2019 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // 		https://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package locations provides functions to get the location of a particular part
    16  // of a descriptor, allowing Problems to be attached to just a descriptor's
    17  // name, type, etc.. This allows for better auto-replacement functionality in
    18  // code review tools.
    19  //
    20  // All functions in this package accept a descriptor and return a
    21  // protobuf SourceCodeInfo_Location object, which can be passed directly
    22  // to the Location property on Problem.
    23  package locations
    24  
    25  import (
    26  	"github.com/jhump/protoreflect/desc"
    27  	dpb "google.golang.org/protobuf/types/descriptorpb"
    28  )
    29  
    30  // pathLocation returns the precise location for a given descriptor and path.
    31  // It combines the path of the descriptor itself with any path provided appended.
    32  func pathLocation(d desc.Descriptor, path ...int) *dpb.SourceCodeInfo_Location {
    33  	fullPath := d.GetSourceInfo().GetPath()
    34  	for _, i := range path {
    35  		fullPath = append(fullPath, int32(i))
    36  	}
    37  	return sourceInfoRegistry.sourceInfo(d.GetFile()).findLocation(fullPath)
    38  }
    39  
    40  type sourceInfo map[string]*dpb.SourceCodeInfo_Location
    41  
    42  // findLocation returns the Location for a given path.
    43  func (si sourceInfo) findLocation(path []int32) *dpb.SourceCodeInfo_Location {
    44  	// If the path exists in the source info registry, return that object.
    45  	if loc, ok := si[strPath(path)]; ok {
    46  		return loc
    47  	}
    48  
    49  	// We could not find the path; return nil.
    50  	return nil
    51  }
    52  
    53  // The source map registry is a singleton that computes a source map for
    54  // any file descriptor that it is given, but then caches it to avoid computing
    55  // the source map for the same file descriptors over and over.
    56  type sourceInfoRegistryType map[*desc.FileDescriptor]sourceInfo
    57  
    58  // Each location has a path defined as an []int32, but we can not
    59  // use slices as keys, so compile them into a string.
    60  func strPath(segments []int32) (p string) {
    61  	for i, segment := range segments {
    62  		if i > 0 {
    63  			p += ","
    64  		}
    65  		p += string(segment)
    66  	}
    67  	return
    68  }
    69  
    70  // sourceInfo compiles the source info object for a given file descriptor.
    71  // It also caches this into a registry, so subsequent calls using the same
    72  // descriptor will return the same object.
    73  func (sir sourceInfoRegistryType) sourceInfo(fd *desc.FileDescriptor) sourceInfo {
    74  	answer, ok := sir[fd]
    75  	if !ok {
    76  		answer = sourceInfo{}
    77  
    78  		// This file descriptor does not yet have a source info map.
    79  		// Compile one.
    80  		for _, loc := range fd.AsFileDescriptorProto().GetSourceCodeInfo().GetLocation() {
    81  			answer[strPath(loc.Path)] = loc
    82  		}
    83  
    84  		// Now that we calculated all of this, cache it on the registry so it
    85  		// does not need to be calculated again.
    86  		sir[fd] = answer
    87  	}
    88  	return answer
    89  }
    90  
    91  var sourceInfoRegistry = sourceInfoRegistryType{}