Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/build/build/blueprint/bootstrap/bpdoc/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 6 kB image not shown  

Quelle  reader.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2019 Google Inc. 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.

package bpdoc

import (
 "fmt"
 "go/ast"
 "go/doc"
 "go/parser"
 "go/token"
 "reflect"
 "regexp"
 "runtime"
 "strings"
 "sync"

 "github.com/google/blueprint/proptools"
)

// Handles parsing and low-level processing of Blueprint module source files. Note that most getter
// functions associated with Reader only fill basic information that can be simply extracted from
// AST parsing results. More sophisticated processing is performed in bpdoc.go
type Reader struct {
 pkgFiles map[string][]string // Map of package name to source files, provided by constructor

 mutex  sync.Mutex
 goPkgs map[string]*doc.Package    // Map of package name to parsed Go AST, protected by mutex
 ps     map[string]*PropertyStruct // Map of module type name to property struct, protected by mutex
}

func NewReader(pkgFiles map[string][]string) *Reader {
 return &Reader{
  pkgFiles: pkgFiles,
  goPkgs:   make(map[string]*doc.Package),
  ps:       make(map[string]*PropertyStruct),
 }
}

func (r *Reader) Package(path string) (*Package, error) {
 goPkg, err := r.goPkg(path)
 if err != nil {
  return nil, err
 }

 return &Package{
  Name: goPkg.Name,
  Path: path,
  Text: goPkg.Doc,
 }, nil
}

func (r *Reader) ModuleType(name string, factory reflect.Value) (*ModuleType, error) {
 f := runtime.FuncForPC(factory.Pointer())

 pkgPath, err := funcNameToPkgPath(f.Name())
 if err != nil {
  return nil, err
 }

 factoryName := strings.TrimPrefix(f.Name(), pkgPath+".")

 text, err := r.getModuleTypeDoc(pkgPath, factoryName)
 if err != nil {
  return nil, err
 }

 return &ModuleType{
  Name:    name,
  PkgPath: pkgPath,
  Text:    formatText(text),
 }, nil
}

// Return the PropertyStruct associated with a property struct type.  The type should be in the
// format <package path>.<type name>
func (r *Reader) propertyStruct(pkgPath, name string, defaults reflect.Value) (*PropertyStruct, error) {
 ps := r.getPropertyStruct(pkgPath, name)

 if ps == nil {
  pkg, err := r.goPkg(pkgPath)
  if err != nil {
   return nil, err
  }

  for _, t := range pkg.Types {
   if t.Name == name {
    ps, err = newPropertyStruct(t)
    if err != nil {
     return nil, err
    }
    ps = r.putPropertyStruct(pkgPath, name, ps)
   }
  }
 }

 if ps == nil {
  return nil, fmt.Errorf("package %q type %q not found", pkgPath, name)
 }

 ps = ps.Clone()
 ps.SetDefaults(defaults)

 return ps, nil
}

// Return the PropertyStruct associated with a struct type using recursion
// This method is useful since golang structs created using reflection have an empty PkgPath()
func (r *Reader) PropertyStruct(pkgPath, name string, defaults reflect.Value) (*PropertyStruct, error) {
 var props []Property

 // Base case: primitive type
 if defaults.Kind() != reflect.Struct || proptools.IsConfigurable(defaults.Type()) {
  props = append(props, Property{Name: name,
   Type: defaults.Type().String()})
  return &PropertyStruct{Properties: props}, nil
 }

 // Base case: use r.propertyStruct if struct has a non empty pkgpath
 if pkgPath != "" {
  return r.propertyStruct(pkgPath, name, defaults)
 }

 numFields := defaults.NumField()
 for i := 0; i < numFields; i++ {
  field := defaults.Type().Field(i)
  // Recurse
  ps, err := r.PropertyStruct(field.Type.PkgPath(), field.Type.Name(), reflect.New(field.Type).Elem())

  if err != nil {
   return nil, err
  }
  prop := Property{
   Name:       strings.ToLower(field.Name),
   Text:       formatText(ps.Text),
   Type:       field.Type.Name(),
   Properties: ps.Properties,
  }
  props = append(props, prop)
 }
 return &PropertyStruct{Properties: props}, nil
}

func (r *Reader) getModuleTypeDoc(pkgPath, factoryFuncName string) (string, error) {
 goPkg, err := r.goPkg(pkgPath)
 if err != nil {
  return "", err
 }

 for _, fn := range goPkg.Funcs {
  if fn.Name == factoryFuncName {
   return fn.Doc, nil
  }
 }

 // The doc package may associate the method with the type it returns, so iterate through those too
 for _, typ := range goPkg.Types {
  for _, fn := range typ.Funcs {
   if fn.Name == factoryFuncName {
    return fn.Doc, nil
   }
  }
 }

 return "", nil
}

func (r *Reader) getPropertyStruct(pkgPath, name string) *PropertyStruct {
 r.mutex.Lock()
 defer r.mutex.Unlock()

 name = pkgPath + "." + name

 return r.ps[name]
}

func (r *Reader) putPropertyStruct(pkgPath, name string, ps *PropertyStruct) *PropertyStruct {
 r.mutex.Lock()
 defer r.mutex.Unlock()

 name = pkgPath + "." + name

 if r.ps[name] != nil {
  return r.ps[name]
 } else {
  r.ps[name] = ps
  return ps
 }
}

// Package AST generation and storage
func (r *Reader) goPkg(pkgPath string) (*doc.Package, error) {
 pkg := r.getGoPkg(pkgPath)
 if pkg == nil {
  if files, ok := r.pkgFiles[pkgPath]; ok {
   var err error
   pkgAST, err := packageAST(files)
   if err != nil {
    return nil, err
   }
   pkg = doc.New(pkgAST, pkgPath, doc.AllDecls)
   pkg = r.putGoPkg(pkgPath, pkg)
  } else {
   return nil, fmt.Errorf("unknown package %q", pkgPath)
  }
 }
 return pkg, nil
}

func (r *Reader) getGoPkg(pkgPath string) *doc.Package {
 r.mutex.Lock()
 defer r.mutex.Unlock()

 return r.goPkgs[pkgPath]
}

func (r *Reader) putGoPkg(pkgPath string, pkg *doc.Package) *doc.Package {
 r.mutex.Lock()
 defer r.mutex.Unlock()

 if r.goPkgs[pkgPath] != nil {
  return r.goPkgs[pkgPath]
 } else {
  r.goPkgs[pkgPath] = pkg
  return pkg
 }
}

// A regex to find a package path within a function name. It finds the shortest string that is
// followed by '.' and doesn't have any '/'s left.
var pkgPathRe = regexp.MustCompile("^(.*?)\\.[^/]+$")

func funcNameToPkgPath(f string) (string, error) {
 s := pkgPathRe.FindStringSubmatch(f)
 if len(s) < 2 {
  return "", fmt.Errorf("failed to extract package path from %q", f)
 }
 return s[1], nil
}

func packageAST(files []string) (*ast.Package, error) {
 asts := make(map[string]*ast.File)

 fset := token.NewFileSet()
 for _, file := range files {
  ast, err := parser.ParseFile(fset, file, nil, parser.ParseComments)
  if err != nil {
   return nil, err
  }
  asts[file] = ast
 }

 pkg, _ := ast.NewPackage(fset, asts, nil, nil)
 return pkg, nil
}

[Dauer der Verarbeitung: 0.20 Sekunden, vorverarbeitet 2026-06-28]